如何使用 React Hooks 单击 clearInterval?
how do I clearInterval on-click, with React Hooks?
我正在尝试重构我的代码以响应挂钩,但我不确定我是否做对了。我尝试将我的 setInterval/setTimout 代码复制并粘贴到挂钩中,但它没有按预期工作。在尝试了不同的方法之后,我能够让它工作,但我不确定这是否是最好的方法。
我知道我可以在卸载时使用useEffect清除间隔,但我想在卸载前清除它。
以下是好的做法吗?如果不是,在卸载前清除 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 ---
使用 Hooks setInterval
的好模式 API:
https://overreacted.io/making-setinterval-declarative-with-react-hooks/
---原始答案---
一些问题:
不要在任何模块的全局范围内使用非常量变量。如果您在一个页面中使用此模块的两个实例,它们将共享这些全局变量。
不需要在else分支中清除定时器,因为如果timerOn
从true变为false,return函数将被执行。
我认为更好的方法:
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);
};
运行 此处示例:
在这个例子中,我们添加了一些东西...
一个 on/off 超时开关('running' arg)将完全打开或关闭它
一个重置函数,允许我们随时将超时设置回0:
如果在 运行 时调用,它会保持 运行 但 return 为 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>
);
}
Demo of clear many timers.
您应该声明并清除 timer.current
而不是 timer
。
- 声明
s
和 timer
。
const [s, setS] = useState(0);
let timer = useRef<NodeJS.Timer>();
- 初始化定时器
useEffect(() => {})
。
useEffect(() => {
if (s == props.time) {
clearInterval(timer.current);
}
return () => {};
}, [s]);
- 清除计时器。
useEffect(() => {
if (s == props.time) {
clearInterval(timer.current);
}
return () => {};
}, [s]);
我正在尝试重构我的代码以响应挂钩,但我不确定我是否做对了。我尝试将我的 setInterval/setTimout 代码复制并粘贴到挂钩中,但它没有按预期工作。在尝试了不同的方法之后,我能够让它工作,但我不确定这是否是最好的方法。
我知道我可以在卸载时使用useEffect清除间隔,但我想在卸载前清除它。
以下是好的做法吗?如果不是,在卸载前清除 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 ---
使用 Hooks setInterval
的好模式 API:
https://overreacted.io/making-setinterval-declarative-with-react-hooks/
---原始答案---
一些问题:
不要在任何模块的全局范围内使用非常量变量。如果您在一个页面中使用此模块的两个实例,它们将共享这些全局变量。
不需要在else分支中清除定时器,因为如果
timerOn
从true变为false,return函数将被执行。
我认为更好的方法:
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);
};
运行 此处示例:
在这个例子中,我们添加了一些东西...
一个 on/off 超时开关('running' arg)将完全打开或关闭它
一个重置函数,允许我们随时将超时设置回0:
如果在 运行 时调用,它会保持 运行 但 return 为 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>
);
}
Demo of clear many timers.
您应该声明并清除 timer.current
而不是 timer
。
- 声明
s
和timer
。
const [s, setS] = useState(0);
let timer = useRef<NodeJS.Timer>();
- 初始化定时器
useEffect(() => {})
。
useEffect(() => {
if (s == props.time) {
clearInterval(timer.current);
}
return () => {};
}, [s]);
- 清除计时器。
useEffect(() => {
if (s == props.time) {
clearInterval(timer.current);
}
return () => {};
}, [s]);