3

I'm using useInterval hook, wrote by Dan Abramov from here

How can I reset counter? As example by click on button?

Code on codesandbox

function Counter() {
  const [count, setCount] = useState(0);

  useInterval(() => {
    // Your custom logic here
    setCount(count + 1);
  }, 1000);

  const resetInterval = () => {};

  return (
    <>
      <h1>{count}</h1>
      <button ocClick={resetInterval}>Reset</button>
    </>
  );
}

4 Answers 4

4

To reset the counter, call setCount(0) from resetInterval:

Note: you misspelled onClick on the button.

function Counter() {
  const [count, setCount] = useState(0);

  useInterval(() => {
    // Your custom logic here
    setCount(count => count + 1);
  }, 1000);

  const resetInterval = () => setCount(0);

  return (
    <>
      <h1>{count}</h1>
      <button onClick={resetInterval}>Reset</button>
    </>
  );
}

To stop/resume the interval you can refactor useInterval to return a toggleRunning function, and the current running status.

function useInterval(callback, delay) {
  const savedCallback = useRef();
  const intervalId = useRef(null);
  const [currentDelay, setDelay] = useState(delay);

  const toggleRunning = useCallback(
    () => setDelay(currentDelay => (currentDelay === null ? delay : null)),
    [delay]
  );

  const clear = useCallback(() => clearInterval(intervalId.current), []);

  // Remember the latest function.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }

    if (intervalId.current) clear();

    if (currentDelay !== null) {
      intervalId.current = setInterval(tick, currentDelay);
    }

    return clear;
  }, [currentDelay, clear]);

  return [toggleRunning, !!currentDelay];
}

Working example with Reset and Pause/Resume (Sandbox)

const { useState, useEffect, useRef, useCallback, Fragment } = React;

function Counter() {
  const [count, setCount] = useState(0);

  const [toggle, running] = useInterval(() => {
    // Your custom logic here
    setCount(count => count + 1);
  }, 100);

  const resetCounter = () => setCount(0);

  return (
    <Fragment>
      <h1>{count}</h1>
      <button onClick={resetCounter}>Reset</button>
      <button onClick={toggle}>{running ? "Pause" : "Resume"}</button>
    </Fragment>
  );
}

function useInterval(callback, delay) {
  const savedCallback = useRef();
  const intervalId = useRef(null);
  const [currentDelay, setDelay] = useState(delay);

  const toggleRunning = useCallback(
    () => setDelay(currentDelay => (currentDelay === null ? delay : null)),
    [delay]
  );

  const clear = useCallback(() => clearInterval(intervalId.current), []);

  // Remember the latest function.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }

    if (intervalId.current) clear();

    if (currentDelay !== null) {
      intervalId.current = setInterval(tick, currentDelay);
    }

    return clear;
  }, [currentDelay, clear]);

  return [toggleRunning, !!currentDelay];
}

ReactDOM.render(<Counter />, root);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

Sign up to request clarification or add additional context in comments.

3 Comments

Nope. Just resets the number to 0.
Are you looking for interval clearing, resetting the number to 0, or both?
It's just you using resetInterval function which reset the counter...
3

In case you want to clearInterval and stop/reset the counter, check the next example:

function Counter() {
  const [count, setCount] = useState(0);

  const intervalId = useRef();

  useEffect(() => {
    intervalId.current = setInterval(() => {
      setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(intervalId.current);
  }, []);

  return (
    <>
      <h1>{count}</h1>
      <button
        onClick={() => {
          setCount(0);
        }}
      >
        Reset Counter and Continue Counting
      </button>
      <button
        onClick={() => {
          setCount(0);
          clearInterval(intervalId.current);
        }}
      >
        Reset and Stop Count
      </button>
      <button
        onClick={() => {
          clearInterval(intervalId.current);
        }}
      >
        Stop Count and Clear Interval
      </button>
    </>
  );
}

Edit Q-56952038-ClearIntervalOnClick

3 Comments

Do we not need clearInterval(intervalId.current) in the "Reset Counter" click handler also?
Depends on what you are trying to do... it's pretty clear if you want to reset the counter and stop it from counting again you can add clearInterval
I guess OP wants to do that, this is why I asked.
0

Just set the state to 0

 const resetInterval = () => {setCount(0)};

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={resetInterval}>Reset</button>
    </div>
  );

It seems that you have mistyped onClick and that is why it wasn't working

Comments

0

As far as I can see, you can use an extra reset state, pass it to useInterval, change this state somehow on every reset change (I am simply incrementing it), then use this state in a ref like callback and compare the current and the old one in useInterval.

import React from "react";
import ReactDOM from "react-dom";

function Counter() {
  const [count, setCount] = React.useState(0);
  const [delay, setDelay] = React.useState(1000);
  const [isRunning, setIsRunning] = React.useState(true);
  const [reset, setReset] = React.useState(0);

  useInterval(() => {
    // Your custom logic here
    setCount(count + 1);
  }, isRunning ? delay : null, reset);

  function handleDelayChange(e) {
    setDelay(Number(e.target.value));
  }

  function handleIsRunningChange(e) {
    setIsRunning(e.target.checked);
  }

  function handleResetChange() {
    setReset(c => c + 1);
    setCount(0);
  }

  return (
    <>
      <h1>{count}</h1>
      <input type="checkbox" checked={isRunning} onChange={handleIsRunningChange} /> Running
      <br />
      <input value={delay} onChange={handleDelayChange} />
      <button onClick={handleResetChange}>Reset</button>
    </>
  );
}

function useInterval(callback, delay, reset) {
  const savedCallback = React.useRef();
  const savedReset = React.useRef();
  // Remember the latest function.
  React.useEffect(() => {
    savedCallback.current = callback;
    savedReset.current = reset;
  }, [callback, reset]);

  // Set up the interval.
  React.useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null || reset !== savedReset.current) {
      let id = setInterval(tick, delay);
      return () => {console.log("cleared", id); clearInterval(id)};
    }
  }, [delay, reset]);
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Counter />, rootElement);

CodeSandbox example

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.