Hyd*_*erA 4 javascript setinterval ecmascript-6 reactjs
let updateTimer: number;
export function Timer() {
const [count, setCount] = React.useState<number>(0);
const [messages, setMessages] = React.useState<string[]>([]);
const start = () => {
updateTimer = setInterval(() => {
const m = [...messages];
m.push("called");
setMessages(m);
setCount(count + 1);
}, 1000);
};
const stop = () => {
clearInterval(updateTimer);
};
return (
<>
<div>{count}</div>
<button onClick={start}>Start</button>
<button onClick={stop}>Stop</button>
{messages.map((message, i) => (
<p key={i}>{message}</p>
))}
</>
);
}
Run Code Online (Sandbox Code Playgroud)
代码示例:https : //codesandbox.io/s/romantic-wing-9yxw8?file=/ src/ App.tsx
该代码有两个按钮 - 开始和停止。
开始调用 asetInterval并保存间隔 ID。定时器设置为 1 秒(1000 毫秒)。
停止clearInterval在间隔 id 上调用 a 。
间隔 id 在组件外声明。
间隔回调函数增加一个计数器并向calledUI附加一条消息。
当我单击“开始”时,我希望计数器每秒递增一次,并called在按钮下方附加相应的消息。
实际发生的情况是,在单击“开始”时,计数器仅递增一次,called消息也是如此。
如果我再次单击“开始”,计数器会递增,然后重置回其先前的值。
如果我一直单击“开始”,计数器会不断增加并重置回其先前的值。
谁能解释这种行为?
您在时间间隔的回调中关闭了count值。
因此,在使用 value 进行第一次状态更新后setState(0+1),您将拥有相同的countvalue 调用setState(0+1),不会触发另一个渲染。
使用没有闭包的使用先前状态值的功能更新:
setCount((count) => count + 1);
Run Code Online (Sandbox Code Playgroud)
同样的原因messages:
setMessages(prev => [...prev,"called"]);
Run Code Online (Sandbox Code Playgroud)
const start = () => {
// should be a ref
intervalId.current = setInterval(() => {
setMessages((prev) => [...prev, "called"]);
setCount((count) => count + 1);
}, 1000);
};
Run Code Online (Sandbox Code Playgroud)
请注意
使用外部作用域变量而不是 的另一个可能的错误useRef,为此阅读了有关useRefvs 变量差异的信息。
作为参考,这是一个简单的计数器切换示例:
function Component() {
// use ref for consisent across multiple components
// see /sf/ask/4021090811/#57444430
const intervalRef = useRef();
const [counter, setCounter] = useState(0);
// simple toggle with reducer
const [isCounterOn, toggleCounter] = useReducer((p) => !p, false);
// handle toggle
useEffect(() => {
if (isCounterOn) {
intervalRef.current = setInterval(() => {
setCounter((prev) => prev + 1);
}, 1000);
} else {
clearInterval(intervalRef.current);
}
}, [isCounterOn]);
// handle unmount
useEffect(() => {
// move ref value into callback scope
// to not lose its value upon unmounting
const intervalId = intervalRef.current;
return () => {
// using clearInterval(intervalRef.current) may lead to error/warning
clearInterval(intervalId);
};
}, []);
return (
<>
{counter}
<button onClick={toggleCounter}>Toggle</button>
</>
);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
134 次 |
| 最近记录: |