如何使用React钩子清除点击插座



我正在尝试重构代码以反应钩子,但是我不确定我是否正确地进行了钩子。我尝试将我的setInterval/settimout代码复制并粘贴到钩子中,但它没有按预期工作。经过不同的事情,我能够使它起作用,但是我不确定这是否是最好的方法。

我知道我可以使用使用效率清除未安装的间隔,但是我想在解开之前清除它。

是以下良好练习,如果没有,请在解开之前清除setInterval/settimout的更好方法?

谢谢,

usetimeout

import { useState, useEffect } from 'react';
let timer = null;
const useTimeout = () => {
    const [count, setCount] = useState(0);
    const [timerOn, setTimerOn] = useState(false);
    useEffect(() => {
        if (timerOn) {
            console.log("timerOn ", timerOn);
            timer = setInterval(() => {
                setCount((prev) => prev + 1)
            }, 1000);
        } else {
            console.log("timerOn ", timerOn);
            clearInterval(timer);
            setCount(0);
        }
    return () => {
        clearInterval(timer);
    }
    }, [timerOn])
    return [count, setCount, setTimerOn];
}
export default useTimeout;

组件

import React from 'react';
import useTimeout from './useTimeout';
const UseStateExample = () => {
    const [count, setCount, setTimerOn] = useTimeout()
    return (
        <div>
            <h2>Notes:</h2>
            <p>New function are created on each render</p>
            <br />
            <h2>count = {count}</h2>
            <button onClick={() => setCount(prev => prev + 1)}>Increment</button>
            <br />
            <button onClick={() => setCount(prev => prev - 1)}>Decrement</button>
            <br />
            <button onClick={() => setTimerOn(true)}>Set Interval</button>
            <br />
            <button onClick={() => setTimerOn(false)}>Stop Interval</button>
            <br />
        </div>
    );
}
export default UseStateExample;

----添加 @ 2019-02-11 15:58 ---

使用钩子API使用setInterval的好模式:

https://overreacted.io/making-setinterval-declarative-with-react-hooks/


---原点答案---

一些问题:

  1. 在任何模块的全局范围中均不使用非恒定变量。如果您在一个页面中使用此模块的两个实例,它们将共享那些全局变量。

  2. 无需在" else"分支中清除计时器,因为如果timerOn从True到False更改,则将执行返回函数。

我的想法更好的方法:

import { useState, useEffect } from 'react';
export default (handler, interval) => {
  const [intervalId, setIntervalId] = useState();
  useEffect(() => {
    const id = setInterval(handler, interval);
    setIntervalId(id);
    return () => clearInterval(id);
  }, []);
  return () => clearInterval(intervalId);
};

在此处运行示例:

https://codesandbox.io/embed/52O442WQ8L?codeMirror=1

在此示例中,我们添加了几件事...

  1. A ON/OFF开关('running'arg)将完全打开或关闭

  2. 重置功能,允许我们随时将超时设置为0:

    如果在运行时调用,它将继续运行,但返回为0。如果在不运行时打电话给它,它将启动它。

const useTimeout = (callback, delay, running = true) => {
  // save id in a ref so we make sure we're always clearing the latest timeout
  const timeoutId = useRef('');
  // save callback as a ref so we can update the timeout callback without resetting it
  const savedCallback = useRef();
  useEffect(
    () => {
      savedCallback.current = callback;
    },
    [callback],
  );
  // clear the timeout and start a new one, updating the timeoutId ref
  const reset = useCallback(
    () => {
      clearTimeout(timeoutId.current);
      const id = setTimeout(savedCallback.current, delay);
      timeoutId.current = id;
    },
    [delay],
  );
  // keep the timeout dynamic by resetting it whenever its' deps change
  useEffect(
    () => {
      if (running && delay !== null) {
        reset();
        return () => clearTimeout(timeoutId.current);
      }
    },
    [delay, running, reset],
  );
  return { reset };
};

因此,在上面的示例中,我们可以像这样使用它...

const UseStateExample = ({delay}) => {
    // count logic
    const initCount = 0
    const [count, setCount] = useState(initCount)
    
    const incrementCount = () => setCount(prev => prev + 1)
    const decrementCount = () => setCount(prev => prev - 1)
    const resetCount = () => setCount(initCount)
    // timer logic
    const [timerOn, setTimerOn] = useState(false)
    const {reset} = useTimeout(incrementCount, delay, timerOn)
    const startTimer = () => setTimerOn(true)
    const stopTimer = () => setTimerOn(false)
    
    return (
        <div>
            <h2>Notes:</h2>
            <p>New function are created on each render</p>
            <br />
            <h2>count = {count}</h2>
            <button onClick={incrementCount}>Increment</button>
            <br />
            <button onClick={decrementCount}>Decrement</button>
            <br />
            <button onClick={startTimer}>Set Interval</button>
            <br />
            <button onClick={stopTimer}>Stop Interval</button>
            <br />
            <button onClick={reset}>Start Interval Again</button>
            <br />
        </div>
    );
}

明确的许多计时器的演示。

您应该声明并清除timer.current而不是timer

  1. 声明stimer
const [s, setS] = useState(0);
let timer = useRef<NodeJS.Timer>();
  1. useEffect(() => {})中初始化计时器。
useEffect(() => {
  if (s == props.time) {
    clearInterval(timer.current);
  }
  return () => {};
}, [s]);
  1. 清除计时器。
useEffect(() => {
  if (s == props.time) {
    clearInterval(timer.current);
  }
  return () => {};
}, [s]);

在许多尝试与setInterval一起工作后,我决定使用settimeout,我希望它对您有用。

  const [count, setCount] = useState(60);
  useEffect(() => {
    if (count > 0) {
      setTimeout(() => {
        setCount(count - 1);
      }, 1000);
    }
  }, [count]);

最新更新