是否使用setTimeout以确保函数在useEffect坏后被调用?



比如我有这样的代码:

const [test, setTest] = useState();
const [test2, setTest2] = useState();
useEffect(() => {
setTest2(undefined);
}, [test]);
const calledFunction => () {
setTest(whatever);
setTest2(thisIsWhatIwant);
}
return (
<>
{test2}
<button onClick={() => calledFunction}></button>
</>
);
在所有这些代码之后,即使我想拥有&;thisiswhatiwant &;,我也会在test2中得到undefined。因此,有一个小技巧可以实现这一点:
const [test, setTest] = useState();
const [test2, setTest2] = useState();
useEffect(() => {
setTest2(undefined);
}, [test]);
const calledFunction = () => {
setTest(whatever);
setTimeout(() => setTest2(thisIsWhatIwant), 1);
}

这将工作,因为setTimeout将把setTest2推到堆栈的末尾(在useEffect之后)。

这种做法不好吗?如果是这样,有什么方法可以更干净地实现我想要的吗?

谢谢。

//edit: callledfunction在点击另一个按钮时被调用

这个问题的模糊性使得这个问题很难回答。我将假设以下场景:

除特殊情况外,如果test改变,则需要重置test2

你可以创建一个自定义setter而不是使用useEffect回调。

const [test, _setTest] = useState();
const [test2, setTest2] = useState();
const setTest = useCallback((newTest) => {
_setTest(newTest);
setTest2(undefined);
}, []);
const calledFunction = () => {
_setTest(whatever);
setTest2(thisIsWhatIwant);
}
return (
<>
{test2}
<button onClick={() => calledFunction}></button>
</>
);
在上面的代码中,我们定义了settersetTest来更新test和重置test2。"正常";代码将调用setTest函数,它与您之前的行为密切相关。

但是在你的特殊情况下,你可以使用_setTest,它只更新test而不重置test2

注意有两个重要区别:

  1. 在组件挂载时不调用自定义设置器。
  2. 如果传递给setTest的值与前一个值具有相同的标识,则不会调用useEffect回调,test2永远不会重置。然而,使用这个自定义setter,test2将被重置,无论如何。

根据上下文,这些行为差异可能相关,也可能不相关。

另一种方法是使用ref,它告诉您想要跳过这种效果的代码。

const [test, setTest] = useState();
const [test2, setTest2] = useState();
const skipSetter = useRef(false);
useEffect(() => {
if(skipSetter.current){
setTest2(undefined);
}
skipSetter.current = false;
}, [test]);
const calledFunction => () {
skipSetter.current = true;
setTest(whatever);
setTest2(thisIsWhatIwant);
}

这和你目前的方法之间的主要区别是,不会有一个额外的渲染,这发生在你的实现中,因为setTimeout回调内部的setState

注意:你必须小心ref变量的值,并确保你在适当的地方设置了正确的值。

最新更新