gpt4 book ai didi

javascript - react ,setInterval 行为

转载 作者:行者123 更新时间:2023-12-03 20:23:52 24 4
gpt4 key购买 nike

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>
))}
</>
);
}
代码示例: https://codesandbox.io/s/romantic-wing-9yxw8?file=/src/App.tsx

该代码有两个按钮 - 开始和停止。
  • 开始调用 setInterval并保存间隔ID。定时器设置为 1 秒(1000 毫秒)。
  • 停止调用 clearInterval在区间 id 上。

  • 间隔 id 在组件外部声明。
    间隔回调函数增加一个计数器并附加一个 called向 UI 发送消息。
    当我点击开始时,我希望计数器每秒递增一次,并且相应的 called按钮下方附加的消息。
    实际发生的是,在单击开始时,计数器只增加一次, called 也是如此。信息。
    如果我再次单击“开始”,计数器会增加并随后重置回之前的值。
    如果我继续单击“开始”,计数器会不断增加并重置回之前的值。
    谁能解释这种行为?

    最佳答案

    你有 closurecount间隔回调中的值。
    因此,在第一次状态更新后,值为 setState(0+1) ,您将拥有相同的 count值(value)电话setState(0+1)这不会触发另一个渲染。
    使用functional updates它使用没有闭包的先前状态值:

    setCount((count) => count + 1);
    messages 的原因相同:
    setMessages(prev => [...prev,"called"]);
    const start = () => {
    // should be a ref
    intervalId.current = setInterval(() => {
    setMessages((prev) => [...prev, "called"]);
    setCount((count) => count + 1);
    }, 1000);
    };
    Edit tender-currying-vqi49

    注意另一个可能的错误
    使用外部范围变量而不是 useRef ,为此请阅读 useRef vs variable differences .

    作为引用,这里是一个简单的计数器切换示例:
    function Component() {
    // use ref for consisent across multiple components
    // see https://stackoverflow.com/questions/57444154/why-need-useref-to-contain-mutable-variable-but-not-define-variable-outside-the/57444430#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>
    </>
    );
    }
    Edit Counter Toggle

    关于javascript - react ,setInterval 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65489257/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com