【问题标题】:React hooks useInterval reset after button click单击按钮后反应挂钩 useInterval 重置
【发布时间】:2021-02-04 09:55:07
【问题描述】:

我有钩子 useInterval,它每 10 秒自动下载一次数据,但是我也有可以在每一刻手动下载数据的按钮。单击按钮时,我正在努力重新启动间隔计时器。所以基本上如果间隔计数到 5,但我同时点击按钮,间隔应该重新开始并在下载数据之前再次开始计数到 ​​10

const useInterval = (callback, delay) => {
    const savedCallback = useRef(callback);

    useEffect(() => {
        savedCallback.current = callback;
    }, [callback]);

    useEffect(() => {
        const tick = () => {
            savedCallback.current();
        }

        if (delay !== null) {
            const id = setInterval(tick, delay);
            return () => clearInterval(id);
        }
    }, [delay]);
};

export default useInterval;

应用部分:

useInterval(() => {
        getMessage();
      }, 10000)

const getMessage = async () => {
    setProcessing(true)
    try {
      const res = await fetch('url')
      const response = await res.json();
      setRecievedData(response)
    }
    catch (e) {
      console.log(e)
    }
    finally {
      setProcessing(false)
    }
  }

const getMessageManually = () => {
    getMessage()
    RESTART INTERVAL
  }

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    您应该添加一个重置函数作为从钩子返回的值。

    我还修复了一些问题并添加了一个卸载处理程序:

    // Usage
    const resetInterval = useInterval(() => ..., DELAY);
    resetInterval(); 
    
    // Implementation
    const useInterval = (callback, delay) => {
      const savedCallbackRef = useRef(callback);
    
      const intervalIdRef = useRef();
    
      useEffect(() => {
        savedCallback.current = callback;
      }, [callback]);
    
      // handle tick
      useEffect(() => {
        const tick = () => {
          savedCallback.current();
        };
    
        if (delay !== null) {
          intervalIdRef.current = setInterval(tick, delay);
        }
    
        const id = intervalIdRef.current;
        return () => {
          clearInterval(id);
        };
      }, [delay]);
    
      // handle unmount
      useEffect(() => {
        const id = intervalIdRef.current;
        return () => {
          clearInterval(id);
        };
      }, []);
    
      const resetInterval = useCallback(() => {
        clearInterval(intervalIdRef.current);
        intervalIdRef.current = setInterval(savedCallback.current, delay)
      }, [delay]);
    
      return resetInterval;
    };
    

    【讨论】:

    • 重置实际上停止但不会开始新的间隔,但由于您的回答,我想出了如何做到这一点,现在一切正常。谢谢!
    【解决方案2】:

    您可以在钩子中添加一个重置函数并返回该函数。重置功能应该清除现有的间隔并开始一个新的。

    这是可以重置和停止的钩子的代码。

    const useInterval = (callback, delay) => {
      const savedCallback = useRef(callback);
      const intervalRef = useRef(null);
    
      useEffect(() => {
        savedCallback.current = callback;
      }, [callback]);
    
      useEffect(() => {
        if (delay !== null) {
          const id = setInterval(savedCallback.current, delay);
          intervalRef.current = id;
          return () => clearInterval(id);
        }
      }, [delay]);
    
      useEffect(()=>{
        // clear interval on when component gets removed to avoid memory leaks
        return () => clearInterval(intervalRef.current);
      },[])
    
      const reset = useCallback(() => {
          if(intervalRef.current!==null){
            clearInterval(intervalRef.current);
            intervalRef.current = setInterval(savedCallback.current,delay)
          }
       });
    
       const stop = useCallback(() => {
          if(intervalRef.current!==null){
            clearInterval(intervalRef.current);
          }     
       })
    
      return {
        reset,
        stop
      };
    };
        
    // usage
    const {reset,stop} = useInterval(()=>{},10000);
    reset();
    stop();
    

    【讨论】:

    • 只是几个错误:clearInterval(intervalRef.current) - 你没有卸载时的参考,intervalRef!==null 总是真实的
    • @DennisVash 谢谢。已更正。但是clearInterval(intervalRef.current) 有效。这里有什么问题。
    【解决方案3】:

    另一种解决方案是删除回调上的 ref,使钩子在每次更改回调时重新开始计数

    所以更新上述解决方案

    // 实现 const useInterval = (回调,延迟) => {

    const intervalIdRef = useRef();

    // 处理刻度 使用效果(()=> { 常量刻度 = () => { 打回来(); };

    if (delay !== null) {
      intervalIdRef.current = setInterval(tick, delay);
    }
    
    const id = intervalIdRef.current;
    return () => {
      clearInterval(id);
    };
    

    }, [延迟]);

    // 处理卸载 使用效果(()=> { 常量 id = intervalIdRef.current; 返回 () => { 清除间隔(id); }; }, []); };

    然后你就可以这样使用了

    const [counter, setCounter] = useState[0]
    const onTimerFinish = useCallback(() => {
      setCounter(counter + 1)
      // setCounter will reset the interval
    }, [counter])
    
    useResetInterval(() => {
      onTimerFinish()
    }, 5000)
    

    【讨论】:

      猜你喜欢
      • 2020-09-25
      • 1970-01-01
      • 2021-08-11
      • 2019-04-21
      • 2022-04-12
      • 2020-07-13
      • 1970-01-01
      • 1970-01-01
      • 2020-11-09
      相关资源
      最近更新 更多