Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.5k views
in Technique[技术] by (71.8m points)

javascript - change the value of useState with setInterval

I have a simple component with useState that increase a counter in each click -

function Counter() {
  let [counter, setCounter] = useState(0);

  const incCounter = () => {
    setCounter(counter + 1);
  };

  return (
    <div className="App">
      <h1>{counter}</h1>

      <button onClick={incCounter}>Inc</button>
    </div>
  );
}

Here is its demo

and now I want to call the increase function each 1 second , so I added this piece of code into the component function -

useEffect(() => {
    setInterval(() => {
      incCounter();
    }, 1000);
  }, []); 

Here is its demo

but I don't see the counter increased in the component.

How should I write it correctly and see the counter increased in each 1 second as expected ?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Issue

You've a stale enclosure of the state value from the render cycle the timer callback was set from.

Solution

Use a functional state update so the state is updated from the previous state, not the state from the render cycle the update was enqueued in. This allows the interval callback and click handler to seamlessly update state, independently from each other.

setCounter(counter => counter + 1);

In fact, you should use a functional state update anytime the next state value depends on any previous state value. Incrementing a counter is the classic example of using functional updates.

Don't forget to return a cleanup function to clear the interval for when the component umnounts.

Full code

function Counter() {
  let [counter, setCounter] = useState(0);

  const incCounter = () => {
    setCounter((counter) => counter + 1);
  };

  useEffect(() => {
    const timerId = setInterval(() => {
      incCounter();
    }, 1000);

    return () => clearInterval(timerId);
  }, []);

  return (
    <div className="App">
      <h1>{counter}</h1>

      <button onClick={incCounter}>Inc</button>
    </div>
  );
}

Demo

Edit change-the-value-of-usestate-with-setinterval


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...