I update state inside useEffect and expect webpage to rerender on every state update but it seems like it only updates once - the last value from for loop. And despite me setting timeout the update and rerender happens instantly. What am I doing wrong?
const [definition, setDefinition] = useState('')
useEffect(() => {
if (startAnimationFinished) return
if (!pathIsActive) return
let newDef
for (let i = 0; i < 150; i ) {
newDef = `M ${i} ${i} L ${i} ${i}`
setTimeout(() => {
setDefinition(newDef)
}, 1000)
}
console.log(newDef);
startAnimationFinished = true
}, [pathIsActive])
return (
<>
<svg
className={'path' (pathIsActive ? ' active' : '')}
xmlns="http://www.w3.org/2000/svg"
style={{ border: '1px solid blue' }}
viewBox={`${-width / 4} ${-width / 4} ${width} ${width}`}
{...props}
>
<path fill='none' stroke="white" width='1'
style={{ filter: "drop-shadow(0px 0px 5px white)" }}
d={definition}
/>
</svg>
</>
CodePudding user response:
- React state updates are batched, meaning multiple subsequent updates are going to trigger only one re-render
- You are effectively scheduling all
setTimeout
s to run at the same time
If you want to update the state in 1 second intervals you can do something like this:
const updateEverySecond = async () => {
let i = 0;
while (i < 150) {
const newDef = `M ${i} ${i} L ${i} ${i}`;
setDefinition(newDef);
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
useEffect(() => {
updateEverySecond();
}, []);
CodePudding user response:
React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
consider updating multiple hooks
in your useEffect
, this will not be good behavior if the component
will be rendered for every update. so once useEffect
ends the component
re render.
here if you want to store all the values without loosing any, because here you are overwritting the value of definition
in every itteration you can declare definition
as array
const [definition, setDefinition] = useState([]);
then update it like this :
let newDef = [];
for (let i = 0; i < 150; i ) {
newDef.push(`M ${i} ${i} L ${i} ${i}`)
}
setDefinition(newDef)
now you have the list of definitions you can display them as you want