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
2 Answers
Reset to default 3The 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 */}
</>
);
}