Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do I clearInterval on-click, with React Hooks?

I'm trying to refactor my code to react hooks, but I'm not sure if i'm doing it correctly. I tried copying and pasting my setInterval/setTimout code into hooks, but it did not work as intended. After trying different things I was able to get it to work, but I'm not sure if this is the best way to do it.

I know i can use useEffect to clear interval on un-mount, but I want to clear it before un-mounting.

Is the following good practice and if not what is a better way of clearing setInterval/setTimout before un-mounting?

Thanks,

useTimeout

import { useState, useEffect } from 'react';

let timer = null;

const useTimeout = () => {
    const [count, setCount] = useState(0);
    const [timerOn, setTimerOn] = useState(false);

    useEffect(() => {
        if (timerOn) {
            console.log("timerOn ", timerOn);

            timer = setInterval(() => {
                setCount((prev) => prev + 1)
            }, 1000);

        } else {
            console.log("timerOn ", timerOn);
            clearInterval(timer);
            setCount(0);
        }
    return () => {
        clearInterval(timer);
    }
    }, [timerOn])

    return [count, setCount, setTimerOn];
}

export default useTimeout;

Component

import React from 'react';
import useTimeout from './useTimeout';

const UseStateExample = () => {
    const [count, setCount, setTimerOn] = useTimeout()
    return (
        <div>
            <h2>Notes:</h2>
            <p>New function are created on each render</p>
            <br />
            <h2>count = {count}</h2>
            <button onClick={() => setCount(prev => prev + 1)}>Increment</button>
            <br />
            <button onClick={() => setCount(prev => prev - 1)}>Decrement</button>
            <br />
            <button onClick={() => setTimerOn(true)}>Set Interval</button>
            <br />
            <button onClick={() => setTimerOn(false)}>Stop Interval</button>
            <br />

        </div>
    );
}

export default UseStateExample;
like image 308
Ar-51 Avatar asked Dec 19 '18 21:12

Ar-51


People also ask

How do you use clearInterval in React?

Clearing setInterval in React To stop an interval, you can use the clearInterval() method. ... useEffect(() => { const interval = setInterval(() => { setSeconds(seconds => seconds + 1); }, 1000); return () => clearInterval(interval); }, []); ...

Can you Memoize a hook React?

The React useMemo Hook returns a memoized value. Think of memoization as caching a value so that it does not need to be recalculated. The useMemo Hook only runs when one of its dependencies update. This can improve performance.

Can button click call useEffect?

In this example, useEffect is passed an empty array, [] . Hence, the effect function will be called only on mount. Click the button and you'll see that the effect function isn't invoked.

How do you make a countdown timer with React hooks?

import React from 'react'; import { useCountdown } from './hooks/useCountdown'; const CountdownTimer = ({ targetDate }) => { const [days, hours, minutes, seconds] = useCountdown(targetDate); if (days + hours + minutes + seconds <= 0) { return <ExpiredNotice />; } else { return ( <ShowCounter days={days} hours={hours} ...


1 Answers

--- added @ 2019-02-11 15:58 ---

A good pattern to use setInterval with Hooks API:

https://overreacted.io/making-setinterval-declarative-with-react-hooks/


--- origin answer ---

Some issues:

  1. Do not use non-constant variables in the global scope of any modules. If you use two instances of this module in one page, they’ll share those global variables.

  2. There’s no need to clear timer in the “else” branch because if the timerOn change from true to false, the return function will be executed.

A better way in my thoughts:

import { useState, useEffect } from 'react';

export default (handler, interval) => {
  const [intervalId, setIntervalId] = useState();
  useEffect(() => {
    const id = setInterval(handler, interval);
    setIntervalId(id);
    return () => clearInterval(id);
  }, []);
  return () => clearInterval(intervalId);
};

Running example here:

https://codesandbox.io/embed/52o442wq8l?codemirror=1

like image 57
李元秋 Avatar answered Oct 12 '22 13:10

李元秋