为多个元素设置超时

问题描述 投票:0回答:1

我映射了一组实体,并为每个实体启动了不同的计时器。但是当时间到期时,两者都会重置(执行时间到的回调函数),但您希望其他计时器继续运行,直到时间用完。我使用了 useRef() 但它没有帮助。请告诉我我做错了什么

const ParentComp = () => <div>
   {
       items.map((el, i) => <ChildComp endTimeCb={}/>)
   }
</div>

const ChildComp = ({endTimeCb}) => {
const timeoutId: any = useRef();
const [isRunning, setIsRunning] = useState(true);
useEffect(() => {
    console.log('use', isRunning, minutesDiff)
    if (isRunning) {
        timeoutId.current = setInterval(() => {
            setCurrentDate(() => {
                console.log(minutesDiff)
                if (minutesDiff < 0) {
                    endTimeCb && endTimeCb();
                    setIsRunning(false);
                }
                return new Date().getTime();
            })
        }, 1000);
        return () => clearInterval(timeoutId);
    } else {
        console.log('cb')
        endTimeCb();
    }
}, [isRunning, minutesDiff, endTimeCb]);

return <></>
}
reactjs settimeout
1个回答
0
投票

使用clearInterval(timeoutId.current):应使用timeoutId.current清除间隔以正确访问间隔ID。

每个组件单独的间隔:由于 useRef 为 ChildComp 的每个实例提供稳定的引用,因此每个组件实例将有自己的间隔 ID,从而防止实例之间的意外干扰。

卸载时正确清理:确保组件卸载时清除间隔,以避免潜在的内存泄漏或意外行为。

useEffect 中的依赖数组:确保依赖数组仅包含必要的依赖项。在这种情况下,包括 isRunning 和 endTimeCb,而 分钟Diff 应在间隔函数内计算。

ParentComp 中的 Key Prop:在映射时为每个子组件使用唯一的键,以确保 React 正确识别每个组件实例。在这里,我使用索引 i 作为键,但如果项目中有唯一标识符,最好使用它。

const ParentComp = () => {
 const items = [];

 return (
  <div>
    {items.map((el, i) => (
     <ChildComp key={i} endTimeCb={() => console.log(`Timer ${i}ended`)}/>
     ))}
   </div>
  );
 };

const ChildComp = ({ endTimeCb }) => {
 const timeoutId = useRef(null);
 const [isRunning, setIsRunning] = useState(true);
 const [currentDate, setCurrentDate] = useState(new Date().getTime());

 useEffect(() => {
  if (isRunning) {
    timeoutId.current = setInterval(() => {
    setCurrentDate((prevDate) => {
      const minutesDiff = /* calculate the difference in minutes here */;
      if (minutesDiff < 0) {
        setIsRunning(false);
        endTimeCb && endTimeCb();
        clearInterval(timeoutId.current); // Clear the interval here
      }
      return new Date().getTime();
    });
   }, 1000);
  }

  return () => clearInterval(timeoutId.current);//Cleanup interval on unmount
 }, [isRunning, endTimeCb]);

 return <></>;
};
© www.soinside.com 2019 - 2024. All rights reserved.