0

I have a setState hook inside forEach loop that should update state after each 1000ms

    useEffect(() => {
            startTypingAnimation("From past to the future");
    }, []);
    function startTypingAnimation(sentence) {
        let wordsArr = sentence.split("");
        let animArr = [];

        wordsArr.forEach((item, index) => {
            setTimeout(() => {
                animArr.push(item);
                setAnimText(animArr);
                console.log("animArr = ", animArr);
                console.log("animText = ", animText);
            }, 1000 * (index + 1));
        });
    }

To make typing effect here:

    <Typography variant="h2" align="right">
        {animText}
    </Typography>

console.log(animArr) shows expectable behavior, but animText shows undefined in each loop.

Why am I getting this behavior?

  • 1
    where are you declaring animText? – user3875913 Jan 13 '21 at 17:40
  • Hello. What happens when you change the line with setAnimText call to look like this setAnimText(animArr.join('')); . You could be getting this error as you are attempting to display an array? Also state updates happen async so there is that as well. – FujiRoyale Jan 13 '21 at 17:40
  • Assuming `animText` is the state variable associated with `setAnimText`, its because state does not update immediately, the updated state will only be available on the **next** render. However, the biggest problem is that you're within a `setTimeout` and due to a stale closure the value of `animText` will **never** be updated with a new value. – Brian Thompson Jan 13 '21 at 17:42
  • 1. animText is declared like let [animText, setAnimText] = useState(); in top of the component 2. When I manually entered values to animText (without timeout) it was ok 3. I thought about that, that's why I asked a question here how to get expected behaviour – Caelum Vallis Jan 13 '21 at 18:02
  • 1
    check this https://stackoverflow.com/questions/37977602/settimeout-not-working-inside-foreach – user3875913 Jan 13 '21 at 18:08
  • State should not be declared as a `let`. It's an antipattern and will only encourage incorrect, mutable behavior. It should always be a `const`. React is designed to work as I've described, and you should not try to circumvent it. See [this question](https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately) for more details. – Brian Thompson Jan 13 '21 at 18:10
  • Ok, thanks to everybody for your answers. – Caelum Vallis Jan 13 '21 at 18:15
  • Off Topic: check this out `for(let i=1; i<=sentence.length; ++i) setTimeout(setAnimText, 1000 * i, sentence.slice(0, i));` or `let part = "", delay = 0; for(let char of sentence) setTimeout(setAnimText, delay += 1000, part += char);` – Thomas Jan 13 '21 at 18:27

0 Answers0