最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to use setInterval with react useEffect hook correctly? - Stack Overflow

programmeradmin1浏览0评论

I tried to create a simple timer app with ReactJS and found the below code on the internet.

Does the function that we passed to the useEffect will execute with the dependency change or does it recreates with every dependency change and then execute?

Also I console log the return function of the useEffect and it runs with every render. Does it run only when the ponent unmount? or with every render?

import { useEffect,  useState } from "react";

const App = () => {
  const [isActive, setIsActive] = React.useState(false);
  const [isPaused, setIsPaused] = React.useState(true);
  const [time, setTime] = React.useState(0);

  React.useEffect(() => {
    let interval = null;

    if (isActive && isPaused === false) {
      interval = setInterval(() => {
        setTime((time) => time + 10);
      }, 10);
    } else {
      clearInterval(interval);
    }
    return () => {
      console.log("cleanup");
      clearInterval(interval);
    };
  }, [isActive, isPaused]);

  const handleStart = () => {
    setIsActive(true);
    setIsPaused(false);
  };

  const handlePauseResume = () => {
    setIsPaused(!isPaused);
  };

  const handleReset = () => {
    setIsActive(false);
    setTime(0);
  };

  return (
    <div className="stop-watch">
      {time}
      <button onClick={handleStart}>start</button>
      <button onClick={handlePauseResume}>pause</button>
      <button onClick={handleReset}>clear</button>
    </div>
  );
};

export default App;

I tried to create a simple timer app with ReactJS and found the below code on the internet.

Does the function that we passed to the useEffect will execute with the dependency change or does it recreates with every dependency change and then execute?

Also I console log the return function of the useEffect and it runs with every render. Does it run only when the ponent unmount? or with every render?

import { useEffect,  useState } from "react";

const App = () => {
  const [isActive, setIsActive] = React.useState(false);
  const [isPaused, setIsPaused] = React.useState(true);
  const [time, setTime] = React.useState(0);

  React.useEffect(() => {
    let interval = null;

    if (isActive && isPaused === false) {
      interval = setInterval(() => {
        setTime((time) => time + 10);
      }, 10);
    } else {
      clearInterval(interval);
    }
    return () => {
      console.log("cleanup");
      clearInterval(interval);
    };
  }, [isActive, isPaused]);

  const handleStart = () => {
    setIsActive(true);
    setIsPaused(false);
  };

  const handlePauseResume = () => {
    setIsPaused(!isPaused);
  };

  const handleReset = () => {
    setIsActive(false);
    setTime(0);
  };

  return (
    <div className="stop-watch">
      {time}
      <button onClick={handleStart}>start</button>
      <button onClick={handlePauseResume}>pause</button>
      <button onClick={handleReset}>clear</button>
    </div>
  );
};

export default App;
Share Improve this question edited Jan 14, 2022 at 11:56 evolutionxbox 4,1326 gold badges38 silver badges57 bronze badges asked Jan 14, 2022 at 11:48 Dinuka DilshanDinuka Dilshan 1,2701 gold badge13 silver badges14 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

The code inside the useEffect hook will run every time a dependency value has been changed. In your case whenever isActive or isPaused changes state.

This means that the reference to the interval will be lost, as the interval variable is redefined.

To keep a steady reference, use the useRef hook to have the reference persist throughout state changes.

const App = () => {
  const [isActive, setIsActive] = useState(false);
  const [isPaused, setIsPaused] = useState(true);
  const [time, setTime] = useState(0);
  const interval = useRef(null)

  useEffect(() => {
    if (isActive && !isPaused) {
      interval.current = setInterval(() => {
        setTime((time) => time + 10);
      }, 10);
    } else {
      clearInterval(interval.current);
      interval.current = null;
    }

    return () => {
      clearInterval(interval.current);
    };
  }, [isActive, isPaused])

  ...
}
import React, { useState, useEffect } from "react";

/**
 * Timer ponent
 * 
 * Displays current time and allows user to enter their name
 */
export default function Timer() {
    const [time, setTime] = useState(0); // current time
    const [name, setName] = useState(""); // user's name

    /**
     * Set up an interval to update the time every second
     * 
     * Returns a function to clear the interval when the ponent unmounts
     */
    useEffect(() => {
        const intervalId = setInterval(() => {
            setTime((prev) => prev + 1);
        }, 1000);

        return () => {
            clearInterval(intervalId);
        };
    // Only run this effect once, on mount
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    /**
     * Handle changes to the input field
     *
     * @param {Object} event - input change event
     */
    const handleChange = ({ target }) => setName(target.value);

    return (
        <>
            <h1>Time: {time}</h1> {/* Display the current time */}
            <input value={name} onChange={handleChange} type="text" /> {/* Display the input field */}
        </>
    );
}
发布评论

评论列表(0)

  1. 暂无评论