说我有一个具有某些异步功能的React组件,例如setTimeOut
函数,该函数在该组件的DOM元素上执行任务。如果在该setTimeOut
期间卸载了组件,如何防止该异步函数触发?由于组件卸载导致DOM元素不再存在,因此触发的结果函数将引发错误。
由于我有一个非常具体但很少见的用例,在上一个问题中基本上没有任何见解,因此我试图提出一个有关此问题的理论方法的一般性问题。我所用的特定用例涉及动画完成后有时在动画过程中卸载了destroy()
图形组件上的pixi-react-fiber
图形组件。我认为这个问题的一般形式应该可以帮助我理解一种方法。
编辑:添加示例
Container.js
const CursorContainer = props => {
const [darkMode, setDarkMode] = useState(props.darkMode)
useEffect(() => {
setDarkMode(props.darkMode)
}, [props.darkMode])
return (
<Cursor darkMode={darkMode} />
)
}
export default CursorContainer
Cursor.js
const TYPE = "Cursor"
export const behavior = {
customDisplayObject: props => new PIXI.Graphics(),
customApplyProps: function (g, _, props) {
const { darkMode } = props
g.clear()
g.beginFill(darkMode ? 0x7225e6 : 0xd3fc03, 1)
g.drawCircle(0, 0, 20)
g.endFill()
setTimeout(() => g.destroy(), 5000)
},
}
const Cursor = CustomPIXIComponent(behavior, TYPE)
export default Cursor
如果切换darkMode
,由于状态更改,Cursor
组件将被卸载并重新安装。如果在5秒钟setTimeOut
内发生这种情况,它将抛出一个错误,因为该组件的graphics
DOM元素将消失,并且没有任何破坏作用。如果已卸载组件,如何防止触发此功能?
答案 0 :(得分:1)
使用ref
来维持对间隔的引用,然后在效果清理回调中清除间隔-
例如
const Component = () => {
const intervalRef = useRef(null);
useEffect(() => {
intervalRef.current = setInterval(() => {}, 1000);
return () => {
clearInterval(intervalRef.current);
}
}, [])
}
使用ref
将使您清除组件中其他处理程序的超时/时间间隔
编辑...
根据您的回复,如果要更新以下内容,则返回超时-
export const behavior = {
customDisplayObject: props => new PIXI.Graphics(),
customApplyProps: function (g, _, props) {
const { darkMode } = props
g.clear()
g.beginFill(darkMode ? 0x7225e6 : 0xd3fc03, 1)
g.drawCircle(0, 0, 20)
g.endFill()
return setTimeout(() => g.destroy(), 5000)
},
}
然后在Cursor
组件中的任何位置,只要您有权访问customApplyProps
,您都可以从其中获取setTimeout引用,例如
intervalRef.current = customApplyProps();
然后在效果中,在返回回调中将其清除-
useEffect(() => {
return () => {
clearInterval(intervalRef.current);
}
}, [])
答案 1 :(得分:0)
如果您使用的是功能组件,则可以在useEffect
挂钩中返回一个清理函数,该组件在卸载时会自动调用。您可以使用clearTimeout
返回的setTimeout
函数,并在该清理函数中调用它。
useEffect(() => {
const timeout = setTimeout(..., ...);
return () => {
clearTimeout(timeout);
};
}, []);
答案 2 :(得分:0)
我认为这里更简单的方法是将功能提升到不会卸载的父组件。然后,您可以在父级中有一个状态来控制是否呈现子级组件,并在调用函数时将该状态用作逻辑门。
答案 3 :(得分:0)
我有一个简单的情景,这就是我的解决方法:
const CursorContainer = props => {
const [darkMode, setDarkMode] = useState(props.darkMode)
useEffect(() => {
let mounted= true;
if(mounted) setDarkMode(props.darkMode)
return () => { mounted=false ; }
}, [props.darkMode])
return (
<Cursor darkMode={darkMode} />
)
}
export default CursorContainer