【发布时间】:2021-07-13 22:05:51
【问题描述】:
我有一个更新状态的useCallback,但是因为它需要该状态作为依赖项,所以它在更新状态时会创建一个无限循环。我在这里使用useImmer,但在使用普通useState 时也会发生这种情况。
const [panels, updatePanels] = useImmer({
activePanel: 0,
validPanels: [],
});
const onValidatePanel = useCallback(isValid => {
const panelIndex = panels.validPanels.indexOf(panels.activePanel);
// Add
if (panelIndex === -1 && isValid) {
updatePanels(draft => {
draft.validPanels.push(draft.activePanel);
});
// Remove
} else if (panelIndex > -1 && !isValid) {
updatePanels(draft => {
draft.validPanels.splice(panelIndex, 1);
});
}
}, [panels]);
基本上,当添加或删除索引时,panels 会发生变化,再次触发 onValidatePanel,然后重新添加索引,如此循环......
我该如何解决这个问题?
【问题讨论】:
-
要么将
panels状态分离为单独的activePanel和validPanels状态,要么不将panels标记为回调的依赖项。我更喜欢前者。 -
您能说明
onValidatePanel回调是如何连接的吗?因为更改panels只会重建回调,但实际上不会触发它... -
我对 immer(或 useImmer 钩子)不是很熟悉,但我的直觉是,如果您可以在功能更新中从草稿中访问
panels状态,则可以完全消除对panels作为依赖,消除依赖循环。 -
如果您想使用先前的状态(例如 panel.validPanels)计算状态的值,我会考虑使用
setState的函数形式。您可以将先前的状态作为 arg 接收,而不是将其指定为依赖项。 (reactjs.org/docs/hooks-reference.html#functional-updates) -
useCallback本身不应触发无限循环。只有当你将它放在useEffect的依赖数组中时才会发生这种情况,并在该效果中称它为 unguarded。我想你有一个,但没有包括它?无论如何,功能状态更新可能是正确的方法,但需要考虑其他事项。
标签: javascript reactjs react-hooks usecallback