如何避免在 React 中不必要地重新渲染组件?

How to avoid unnecessary re-render of a component in React?

我有这个案例:

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

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

如何解决这个问题?

这就是React.memo or useMemo的目的。

示例

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) {
  /* ... */
});

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

const Child2 = ({ setValue }) => {
  ....
};

export default memo(Child2);

演示

演示 Child 2 的 2 个“实例”,一个用 memo HOC 装饰,另一个没有。所有子项在呈现时都使用 useEffect 进行记录。请注意,所有初始渲染,但只有子 1 和 2(w/o 备忘录)不断重新渲染。

沙盒代码:

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>
  );
}