在异步clickHandler中卸载组件后调用setState时,会在控制台中引起警告:
Warning: Can't perform a React state update on an unmounted component.
function App() {
const [show, setShow] = useState(true)
return {show && <Button
text="Click to remove"
clickHandler={() => setShow(false)}
/> }
}
function Button({ text, clickHandler }) {
const [state, setState] = useState(text);
const handleClick = async () => {
await clickHandler();
setState("I was clicked");
};
return <button onClick={handleClick}> {state}</button>;
}
单击click to remove
按钮将卸载该按钮,然后更新状态。
目标是在异步调用之后 设置按钮组件的状态。该异步调用可以但不必触发按钮被卸载。我正在寻找一种在异步调用后退出setState
的方法。
我看不到如何使用useEffect很好地避免这种情况。
该示例中有两种可能的解决方法。
人们使用useRef
检查组件是否已卸载(如#14369 (comment)中的建议)。这感觉不太像反应。
另一个解决方法是使用推荐的useEffect
保护变量(例如#14369 (comment))。但是要使clickHandler脱离useEffect
,clickHandler会存储在一个状态中。但是,要使一个函数进入状态,必须将其包装在另一个函数中,因为setState
的{{1}}函数将调用作为参数给出的函数。
答案 0 :(得分:0)
这是一个很好的问题,我不知道为什么它没有引起任何注意。我相信我找到了一个不错的解决方案,如果您认为这可以解决问题,请告诉我。该解决方案基于以下事实:我们可以使用useRef()
而无需在任何地方使用ref属性。
我们定义了两个自定义钩子useIsMountedRef
和useStateWithMountCheck
。您可以像使用useState
钩子一样使用后者,如果不再安装组件,它将忽略所有要求的状态更改。
function useIsMountedRef(){
const ref = useRef(null);
ref.current = true;
useEffect(() => {
return () => {
ref.current = false;
}
});
return ref;
}
function useStateWithMountCheck(...args){
const isMountedRef = useIsMountedRef();
const [state, originalSetState] = useState(...args);
const setState = (...args) => {
if (isMountedRef.current) {
originalSetState(...args);
}
}
return [state, setState];
}