【问题标题】:How to avoid unnecessary re-render of a component in React?如何避免在 React 中不必要地重新渲染组件?
【发布时间】:2021-12-25 00:24:44
【问题描述】:

我有这种情况:

const Parent = () => {
  
  const [value, setValue] = useState('');
  
  return <>
    <Child1 value={value} />
    <Child2 setValue={setValue} />
    </>
  
}

但是每次调用setValuesetValue 时,Child2 都会重新渲染,尽管它的道具没有改变(Child1 也会重新渲染,但这是自道具value 改变后的预期行为) .

如何解决这个问题?

【问题讨论】:

    标签: reactjs react-hooks components rerender


    【解决方案1】:

    这是React.memouseMemo的目的。

    例子

    const Parent = () => {
      
      const [value, setValue] = useState('');
      const child2 = useMemo(() => <Child2 setValue={setValue} />, [setValue])
      
      return <>
        <Child1 value={value} />
        {child2}
        </>
      
    }
    

    [setValue] 是依赖数组。更改此数组中的任何内容都会导致重新计算该值。

    即使道具没有改变,它也会重新渲染的原因是因为您正在更改父组件的状态。这会导致 Parent 组件重新渲染,这将重新渲染所有子组件,而不管它们的 props 是否发生变化。

    或者,您可以像这样在子组件上使用 React.memo:

    const Child2 = React.memo(function Child2(props) {
      /* ... */
    });
    

    【讨论】:

      【解决方案2】:

      React useState 状态更新函数保证是稳定的引用,所以 Child2 只是重新渲染,因为父组件 Parent 由于状态更新而重新渲染。如果您想向 React 提示它可能会放弃重新渲染子组件,请使用 memo 高阶组件。

      const Child2 = ({ setValue }) => {
        ....
      };
      
      export default memo(Child2);
      

      演示

      展示了 Child 2 的 2 个“实例”,一个用 memo HOC 装饰,另一个没有。所有孩子在渲染时都使用useEffect 来记录。请注意,所有最初都呈现,但只有子 1 和 2(无备忘录)不断重新呈现。

      沙盒代码:

      import { memo, useEffect, useState } from "react";
      import "./styles.css";
      
      const Child1 = ({ value }) => {
        useEffect(() => console.log("Child 1 rendered"));
        return <div>Child1: {value}</div>;
      };
      
      const Child2 = ({ id, setValue }) => {
        useEffect(() => console.log(`${id} rendered`));
        return (
          <div>
            {id}: <input type="text" onChange={(e) => setValue(e.target.value)} />
          </div>
        );
      };
      
      const Child2wMemo = memo(Child2);
      
      const Parent = () => {
        const [value, setValue] = useState("");
      
        return (
          <>
            <Child1 value={value} />
            <Child2 id="Child 2" setValue={setValue} />
            <Child2wMemo id="Child 2 with Memo" setValue={setValue} />
          </>
        );
      };
      
      export default function App() {
        return (
          <div className="App">
            <Parent />
          </div>
        );
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-13
        • 2021-01-14
        • 2020-01-10
        • 1970-01-01
        • 2020-12-21
        • 2020-07-26
        • 1970-01-01
        • 2019-04-27
        相关资源
        最近更新 更多