【问题标题】: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} />
</>
}
但是每次调用setValue 的setValue 时,Child2 都会重新渲染,尽管它的道具没有改变(Child1 也会重新渲染,但这是自道具value 改变后的预期行为) .
如何解决这个问题?
【问题讨论】:
标签:
reactjs
react-hooks
components
rerender
【解决方案1】:
这是React.memo或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) {
/* ... */
});
【解决方案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>
);
}