Confused by useEffect in React

I'm confused on how useEffect actually works. I know useEffect is used to trigger some sort of 'side effect' after the changes are committed to the browser. I'm creating a typewriter effect for an example here and I'm confused on the dependency array of useEffect. Obviously, whatever you pass to the dependency array is what will call the useEffect again if said value changes / updates. But why does this typewriter effect not work if I remove index from the dependency array? If I remove it from the dependency array, it'll print out the first letter countless times. It's not actually updating the index state and instead using the old value. My understanding of useEffect is that as long as it reruns it'll use the updated state values in the component, even if it's not in the dependency array. This doesn't seem to be the case. So if any value is needed in useEffect I must pass it to the dependency array if I need its updated values after rerenders? Example:
export const useTypewriter = (text, delay = 500) => {
const [display, setDisplay] = useState("");
const [index, setIndex] = useState(0);

useEffect(() => {
const timeoutId = setInterval(() => {
if (index < text.length) {
setDisplay((previous) => previous + text[index]);
setIndex((previous) => previous + 1);
}
}, delay);

return () => clearTimeout(timeoutId);
}, [text, delay, index]); // If I remove index here it'll print out the first letter over and over

return display;
};
export const useTypewriter = (text, delay = 500) => {
const [display, setDisplay] = useState("");
const [index, setIndex] = useState(0);

useEffect(() => {
const timeoutId = setInterval(() => {
if (index < text.length) {
setDisplay((previous) => previous + text[index]);
setIndex((previous) => previous + 1);
}
}, delay);

return () => clearTimeout(timeoutId);
}, [text, delay, index]); // If I remove index here it'll print out the first letter over and over

return display;
};
12 Replies
i_lost_to_loba_kreygasm
I wish you made a codesandbox so I or others could take a look into it 🙂
vince
vinceOP2w ago
Sure, it's more of a conceptual question but here it is in action: https://codesandbox.io/p/sandbox/dlcgx5 It's under hooks/useTypewriter.js Another question I have is why we even need to use useEffect here at all? The React docs say that useEffect should be used when syncing React to an external system (like a backend / api calls). Here I thought we could just use a setTimeout without the useEffect but I couldn't get that to work, and all the solutions online that I saw use useEffect. I figured if we have a setTimeout without one then we can update the state inside that timeout and it would still trigger a rerender (since the state changes) but that didn't seem to be the case
! Nakoshi 恨
! Nakoshi 恨2w ago
There are 2 use cases for useEffect First one is to use for first rendering. There sometimes makes problem so I usually use useLayoutEffect Second one is to get data according to dependencies If you have any questions feel free to ask
vince
vinceOP2w ago
Doesn't answer my questions if I'm being honest but ty!
Sleep Twitch
Sleep Twitch2w ago
Why don't you just use css for a typewriter animation? Like so: https://css-tricks.com/snippets/css/typewriter-effect/
Geoff Graham
CSS-Tricks
Typewriter Effect | CSS-Tricks
Some use JavaScript, which may sometimes be preferable (literally adding a character at a time feels more like a real typewriter) and sometimes not be
vince
vinceOP2w ago
I didn't even know that was a thing you could do in css, thank you haha
clevermissfox
clevermissfox2w ago
GSAP also might make this easier , I think it's called splitType
vince
vinceOP2w ago
Yea I got it working with React it's moreso a question of useEffect
clevermissfox
clevermissfox2w ago
Whoops just FYI, correction its splitText not splitType
SplitText | GSAP | Docs & Learning
SplitText makes it easy to break apart the text in an HTML element so that each character, word, and/or line is in its own ``, making complex animation simple.
Sleep Twitch
Sleep Twitch2w ago
I get that. I can't answer that question since I don't use react. But isn't this a bad thing to use react for? You don't want to rerender the component every time a new letter has to appear. I believe using css is much lighter. But I could be wrong
vince
vinceOP2w ago
I think you're right honestly I had no idea this could even be done with css otherwise I would have, it's gotta be faster / more lightweight to compute
Sleep Twitch
Sleep Twitch2w ago
Css is very powerful nowadays. And otherwise you have things like GSAP I would look for if you want to animate stuff. They probably have optimized the thing you want for performance, so you gotta take advantage of that. No need to reinvent the wheel that is already almost perfect

Did you find this page helpful?