I want to create a text where's another letter is added to the last one, like in an old computer. But the letters keeps replacing one another instead of adding to one another:
const App = () => {
const [text, setText] = React.useState(``);
React.useEffect(() => {
[`x`,`y`].forEach((letter, index) => {
setTimeout(()=> {
// old: setText(text => text letter)
setText(text => text letter) // new: printing each letter twice
}, 500 * index)
})
}, [])
return (text)
}
ReactDOM.createRoot(document.getElementById(`root`))
.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
<div id="root"></div>
What's the way to fix it?
Thanks!
CodePudding user response:
This is because of StrictMode. Using useEffect dont forget the cleanup function. In this case you need to cleanup timeouts or they will stack up when the component re-render and will survive of an unmount:
React.useEffect(() => {
let ids = [];
['x', 'y'].forEach((letter, index) => {
const id = setTimeout(() => {
setText(text => text letter);
}, 500 * index);
ids.push(id);
});
// cleanup !
return () => { ids.forEach((id) => clearTimeout(id)); };
}, [])
CodePudding user response:
your big mistake is that you didn't work on previous value of state, you make an update on your state value in every render not the previous value of state I belive your mistake will be solved by using a callback in the setText() :
setTimeout(()=> {
setText((prev)=>prev letter)
}, 500 * index)