当 React 功能组件重新渲染时,它会重新分配分配的值和功能吗?

Posted

技术标签:

【中文标题】当 React 功能组件重新渲染时,它会重新分配分配的值和功能吗?【英文标题】:When React functional component re-render, does it reassign assigned values & functions? 【发布时间】:2021-06-02 16:54:56 【问题描述】:

如果这样的代码通过useEffect的依赖重新渲染,

// ...
const Test = () => 
  // ...
  
  const value1 = "test1"
  
  const func1 = () => 
    // do something1
  
  
  useEffect(() => 
    const value2 = "test2"
  
    const func2 = () => 
      // do something2
    
  , [sth])
  
  return (
    // ...
  )

value1 & value2 & func1 & func2 是否重新分配给内存?

我很好奇,和优化有关。

【问题讨论】:

【参考方案1】:

简短的回答,是的。每次函数运行时,旧值都会被垃圾回收,新的原始值将被分配到内存中,并且会为函数和对象创建新的引用。

但“不那么短”答案的真正问题是“它是否会显着影响性能?”。答案是……取决于。在大多数情况下,它不会 (see the doc about it)。但是在某些情况下,您需要进行一些更改才能使用useCallback 进行性能优化并使用useMemo

还值得一提(如Shivam Jha's answer 中所述)useEffect 中的触发器不一定会导致重新渲染(DOM 绘制),因为此过程首先发生在虚拟 DOM 上,并且只会在真实的 DOM 中持续存在必要时使用 DOM。

我将在此处留下一些关于此讨论的其他参考资料。

Dan Abramov's tweet on memoizing everything(也看看回复)

Kent C. Dodds's article about render performance

Felix Gerschau's article about when render occurs

【讨论】:

【参考方案2】:

value1 & value2 & func1 & func2 是否重新分配给内存?

简而言之,答案是肯定的。

如果你看它是什么会更清楚:Test 是一个函数,所以每次调用该函数时,函数范围内的所有变量(大括号)都会重新声明和重新分配。

让我们深入了解细节:

value1func1 在函数体中,因此每次调用函数时都会声明和分配它们,它们根本不相关,它们只是同名。

value2func2 是在一个 useEffect 钩子中声明的,并声明了依赖项 (sth),这意味着这两个变量仅在第一次渲染之后重新声明和重新分配,如果 @与之前的渲染相比,987654327@ 变量的值发生了变化。

如果您想优化 value1 使其在每次渲染时都不会改变,您可以这样使用 useMemo 挂钩:

const value1 = React.useMemo(() => 
  return "test1"; //here you might have a more complicate way to determine value1
, []); //array of dependencies like for `useEffect`, so `value1` will be recalculated only if any of the values provided in here change. by leaving it empty value1 will always be the **same** variable

您也可以使用 useCallback 钩子对函数进行类似的优化

【讨论】:

【参考方案3】:

根据文档:

useEffect 有什么作用?通过使用这个 Hook,你告诉 React 你的组件需要在渲染之后做一些事情。 React 会记住您传递的函数(我们将其称为“效果”),并在执行 DOM 更新后稍后调用它。在这个效果中,我们设置了文档标题,但我们也可以执行数据获取或调用其他一些命令式 API。

此外,它不会re-renders 代码,而是在传递给它的依赖项发生更改时再次运行代码

Tip: Optimizing Performance by Skipping Effects 描述了由于在每次渲染后清理或应用效果而导致的性能问题。

此外,您可以释放分配的内存(如果未自动释放)或在运行代码 (setTimeOut, etc) 后使用 useEffect with cleanup 运行一些副作用。 基本上在 return 函数中执行 useEffect 之后要运行的所有操作:

  useEffect(() => 
    function handleStatusChange(status) 
      setIsOnline(status.isOnline);
    
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() 
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    ;
  );

【讨论】:

以上是关于当 React 功能组件重新渲染时,它会重新分配分配的值和功能吗?的主要内容,如果未能解决你的问题,请参考以下文章

React Hook 功能组件防止重新渲染

React 功能组件在重新挂载后停止渲染状态更改

React 啥时候重新渲染子组件?

重新渲染 Reactjs 后,父组件立即失去状态

如何通过使用功能组件更新 React 中的状态来重新渲染页面。?

如何防止我的功能组件使用 React 备忘录或 React 钩子重新渲染?