反应setInterval行为 [英] React setInterval Behavior

查看:42
本文介绍了反应setInterval行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 让updateTimer:数字;导出函数Timer(){const [count,setCount] = React.useState< number>(0);const [messages,setMessages] = React.useState< string []>([]);const start =()=>{updateTimer = setInterval(()=> {const m = [...消息];m.push(称为");setMessages(m);setCount(count + 1);},1000);};const stop =()=>{clearInterval(updateTimer);};返回 (<>< div> {count}</div>< button onClick = {start}>开始</button>< button onClick = {stop}>停止</button>{messages.map((message,i)=>(< p key = {i}> {消息}</p>))}</>);} 

代码示例:


通知另一个可能的错误请使用外部作用域变量而不是 useRef ,以了解有关

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>
      ))}
    </>
  );
}

Code Sample: https://codesandbox.io/s/romantic-wing-9yxw8?file=/src/App.tsx


The code has two buttons - Start and Stop.

  • Start calls a setInterval and saves interval id. Timer set to 1 second (1000 ms).

  • Stop calls a clearInterval on the interval id.

The interval id is declared outside the component.

The interval callback function increments a counter and appends a called message to the UI.

When I click on Start, I expect the counter to increment every second and a corresponding called message appended underneath the buttons.

What actually happens is that on clicking Start, the counter is incremented just once, and so is the called message.

If I click on Start again, the counter is incremented and subsequently reset back to its previous value.

If I keep clicking on Start, the counter keeps incrementing and resetting back to its previous value.

Can anyone explain this behavior?

解决方案

You have closure on count value inside the interval's callback.

Therefore after the first state update with value setState(0+1), you will have the same count value call setState(0+1) that won't trigger another render.

Use functional updates which uses the previous state value without closures:

setCount((count) => count + 1);

Same reason for messages:

setMessages(prev => [...prev,"called"]);

const start = () => {
  // should be a ref
  intervalId.current = setInterval(() => {
    setMessages((prev) => [...prev, "called"]);
    setCount((count) => count + 1);
  }, 1000);
};


Notice for another possible bug using an outer scope variable instead of useRef, for this read about useRef vs variable differences.


For a reference, here is a simple counter toggle example:

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>
    </>
  );
}

这篇关于反应setInterval行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆