If you don't put a setTimeout or setInterval inside useEffect, it will be reinitialized and not cleaned up every time your component rerenders.
Look at the below example. Every time you increment the counter by pressing the button, the parent component rerenders, which trickles rerenders to all children (including my setTimeout component). Press the button a few times, you will see the component rerenders several times, and then you will see the 'timeout finished' several times.
Then below I have added a snippet with useEffect, you will see the timeout only runs the one time.
Does this answer your question?
edit: Here is a codesandbox to try them out https://codesandbox.io/s/boring-liskov-4kjgm?fontsize=14&hidenavigation=1&theme=dark
without useEffect
import React, {useState} from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [counter, increment] = useState(0);
const doIncrement = () => increment(counter + 1);
return (
<div className="App">
<Counter counter={counter} increment={doIncrement} />
<OtherComponent />
</div>
);
}
const Counter = ({counter, increment}) => {
return <button onClick={()=>increment()}>{counter}</button>
}
const OtherComponent = () => {
console.log('I rerendered');
const timeout = setTimeout(() => console.log('timeout finished'), 1000)
return <h1> Hello world </h1>
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
With useEffect
import React, {useState, useEffect} from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [counter, increment] = useState(0);
const doIncrement = () => increment(counter + 1);
return (
<div className="App">
<Counter counter={counter} increment={doIncrement} />
<OtherComponent />
</div>
);
}
const Counter = ({counter, increment}) => {
return <button onClick={()=>increment()}>{counter}</button>
}
const OtherComponent = () => {
console.log('I rerendered');
useEffect(() => {
const timeout = setTimeout(() => console.log('timeout finished'), 1000)
return () => clearTimeout(timeout)
}, [])
return <h1> Hello world </h1>
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);