countdown minus 2 every 1s. But if i clean up setTimeout, code run correctly. Can anyone explain? My result: https://www.youtube.com/watch?v=NUE-nSLJbiY
const tabs = ['posts', 'comments', 'albums'];
const [title, setTitle] = useState('');
const [posts, setPosts] = useState([]);
const [type, setType] = useState('posts');
const [show, setShow] = useState(false);
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/${type}`)
.then(res => res.json())
.then(post => {
setPosts(post);
})
}, [type])
useEffect(() => {
document.title = title;
})
const [countdown, setCountdown] = useState(180);
useEffect(() => {
const id = setTimeout(() => {
setCountdown(prev => prev - 1);
console.log(countdown);
}, 1000);
// return () => {
// clearTimeout(id)
// }
})
CodePudding user response:
useEffect runs on every render. That means that when every value changes, a render happens, which then triggers another effect.
This is not what we want. There are several ways to control when side effects run.
We should always include the second parameter which accepts an array. We can optionally pass dependencies to useEffect in this array.
If you want to change countdown just after its value update, you should add dependencies to useEffect like this:
useEffect(() => {
const id = setTimeout(() => {
setCountdown(prev => prev - 1);
console.log(countdown);
}, 1000);
// return () => {
// clearTimeout(id)
// }
}, [countdown])
Above code runs on the first render and any time countdown value changes. In fact when the countdown decreases the top useEffect triger too.
useEffect(() => {
document.title = title;
}) //has no dependency
then the document title were change which cause another render. so you are in a loop which cause decrement 2 for value of countdown.