1

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)
        // }
    })
8
  • So, you are saying that the countdown is decremented by 2 every time instead of one? Commented Jan 2, 2022 at 11:35
  • I guess setInterval and clearInterval might be what you're looking for. Commented Jan 2, 2022 at 11:37
  • I can use setInterval to build this clock. But i wanna try with setTimeout Commented Jan 2, 2022 at 11:42
  • your code is working here, decrementing minus 1 every second. or what do you want? Commented Jan 2, 2022 at 11:46
  • it minus 2 every second. i have up my video for that bug Commented Jan 2, 2022 at 12:15

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.