我的
<App />
组件有 2 个状态。第一个状态在用户交互时更新,然后使用 useEffect()
钩子触发第二个状态的更新。这会在用户单击按钮时导致 2 次重新渲染。有人可以帮我弄清楚如何在第二次状态更新后重新渲染 <App />
吗?这是一个糟糕的反应模式吗?
这里是codesandbox:https://codesandbox.io/s/wispy-butterfly-nm5fsr
您可以查看控制台以查看重新渲染。
我需要解决这个问题的原因是因为我有一个真实的项目,其中正在发生重新渲染并且在组件之间传递非常大的道具。重新渲染导致明显的延迟。我会分享整个项目,但这对于堆栈溢出问题来说太多了。
它渲染两次,因为每次渲染更新一次状态,而不是同时更新两个状态。考虑一下你在这里做什么:
const handleClick = () => {
if (state1) setState1((prev) => prev + 1);
else setState1(1);
};
useEffect(() => {
if (state1) setState2(state1 + 10);
}, [state1]);
这基本上意味着:
更新
并重新渲染。在下一次渲染时,更新state1
并重新渲染。state2
获取状态更新的计算并不是非常复杂。将
1
添加到数字,并将 10
添加到数字。您无需等待组件重新渲染即可知道 state1
是什么。它将是当前值加1,这很容易计算。您可以使用该计算来更新这两个状态:
const handleClick = () => {
if (state1) {
const newState1 = state1 + 1;
setState1(newState1);
setState2(newState1 + 10);
} else {
setState1(1);
setState2(10);
}
};
或者,更好,您一开始就不需要两个状态值。在这个例子中,
state2
是派生自state1
(这样做并不是一个困难或昂贵的计算)。这意味着您正在重复状态。
不要重复状态。只需从
state1
导出第二个值:
const [state1, setState1] = useState(null);
const handleClick = () => {
if (state1) setState1((prev) => prev + 1);
else setState1(1);
};
return (
<div className="App">
{console.log("Rerendering children...")}
<Child1 state1={state1} />
<Child2 state2={state1 ? state1 + 10 : null} />
<button type="button" onClick={handleClick}>
Change State 1!
</button>
</div>
);