Javascript 我如何安全地将setTimout与refs inside useffect结合使用?

Javascript 我如何安全地将setTimout与refs inside useffect结合使用?,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我在函数组件中有以下钩子 useffect(()=>{ 如果(已最小化){ //最小化时,延迟将元素交换到最小化节点。 //这将使视频播放时间和效果最小化 //在一个更无缝的视频交换 如果(videoMinimizedRef.current!==null){ 设置超时(()=>{ setOuterContainer(最小化视频参考电流); },视频\u覆盖\u视频\u元素\u交换\u超时); } }否则{ //最大化时,立即将视频元素交换到最大化 //节点。这确保视频元素在动画开始时出现。 如果

我在函数组件中有以下钩子

useffect(()=>{
如果(已最小化){
//最小化时,延迟将元素交换到最小化节点。
//这将使视频播放时间和效果最小化
//在一个更无缝的视频交换
如果(videoMinimizedRef.current!==null){
设置超时(()=>{
setOuterContainer(最小化视频参考电流);
},视频\u覆盖\u视频\u元素\u交换\u超时);
}
}否则{
//最大化时,立即将视频元素交换到最大化
//节点。这确保视频元素在动画开始时出现。
如果(videoMaximizedCallbackRef!==null){
setOuterContainer(videoMaximizedCallbackRef);
}
}
},[isMinimized,setOuterContainer,videoMinimizedRef,videoMaximizedCallbackRef];
isMinimized、setOuterContainer、videoMinimizedRef
都是传递给组件的道具

  • isMinimized
    是一个布尔值
  • setOuterContainer
    是一个useState setter函数,它接收HTMLElement并将其设置为正在播放的视频元素的新父节点
  • videoMinimizedRef
    是播放最小化视频时对视频容器的引用
videoMaximizedCallbackRef
是在此组件中设置的回调ref(没有
.current

钩子按原样工作,完全符合我的要求。也就是说,我意识到这个钩子有一些问题(至少从阅读React钩子文档和常见问题来看是这样)。例如,没有清除setTimeout。可以这样添加:

useffect(()=>{
让超时;
如果(已最小化){
//最小化时,延迟将元素交换到最小化节点。
//这将使视频播放时间和效果最小化
//在一个更无缝的视频交换
如果(videoMinimizedRef.current!==null){
超时=设置超时(()=>{
setOuterContainer(最小化视频参考电流);
},视频\u覆盖\u视频\u元素\u交换\u超时);
}
}否则{
//最大化时,立即将视频元素交换到最大化
//节点。这确保视频元素在动画开始时出现。
如果(videoMaximizedCallbackRef!==null){
setOuterContainer(videoMaximizedCallbackRef);
}
}
return()=>clearTimeout(超时);
},[isMinimized,setOuterContainer,videoMinimizedRef,videoMaximizedCallbackRef];
但是添加这一点会导致每次依赖项发生更改时都会清除超时。我需要确保超时在启动时从未被清除,因为它会导致视频交换在不完全正确的情况下发生

VIDEO\u OVERLAY\u VIDEO\u ELEMENT\u SWAP\u超时
ms

VIDEO\u OVERLAY\u VIDEO\u ELEMENT\u SWAP\u超时+先前清除的设置超时中经过的时间总和
ms

如何编写这个钩子以避免过时闭包和不必要的
clearTimeout
调用的陷阱


我想遵守钩子和穷尽依赖的规则,但这对我来说有点太过分了。

你这样做会很好。设置间隔时,这不是正确的方法,但对于超时,它就像一个符咒

useEffect(() => {
  let timeout;
  timeout = setTimeout(() => {
    // set timeout callback, write your code here
  }, 100)

  return () => {
    clearTimeout(timeout)
  }
}, [yourDependencies])

您可以从dan abramov的博客中阅读更多内容:

如果您有一个超时的事件,但您也可以清除该事件,这表明使用需要考虑使用

间隔计时器设置一次,并按间隔重复

tRef = setInterval(theFuncCall,timeMills)
以及澄清

clearInterval( tRef );

如果您正在查看100毫秒的调用间隔,那么您应该使用
setInterval
作为控制计时的选项。

您不也应该在延迟函数中检查组件在更改状态之前是否已卸载吗?是的,我猜?因为videoMinimizedRef.current在执行超时时可能为null,因为常规的react ref(与回调ref相反)可以自由地变异内部的值,并且不会在钩子中过时?我不确定。这对我来说不起作用,因为钩子渲染了两次
isMinimized
videoMaximizedNode
道具更新(isMinimized从true变为false,videoMaximizedNode从null变为HtmlLevel)。我不想清除一次超时,因为视频节点移动太晚,在动画期间不会出现。我在本地观察到了这一点,那么你应该将其转移到另一个useEffect。我希望这会奏效。