I tried to make a nice animating example for myself using Hooks but I have stumbled upon a problem where my functions won't have the updated version of a state var and continue to use the first version.
In the snippet below I have an example where once you click on a bar it's supposed to move in a square formation. First going east, then south, then west, then north and then east again etc. However it never goes south because even though its direction is updated from north
to east
(indicated by the text on the bar or clicking on it again), the functions still think that the direction is north.
const Example = (props) => {
const [ direction, setDirection ] = React.useState('North');
console.log("Rendering Example: ", direction);
const isAnimating = React.useRef(false)
const blockRef = React.useRef(null);
// Animate on click.
const onClick = () => {
if (!isAnimating.current) {
decideDirection();
isAnimating.current = true
} else {
console.log("Already animating. Going: ", direction);
}
};
const decideDirection = () => {
console.log("Current direction: ", direction);
if (direction === 'North') {
moveEast();
} else if (direction === 'East') {
moveSouth();
} else if (direction === 'South') {
moveWest();
} else if (direction === 'West') {
moveNorth();
}
};
const move = (toX, toY, duration, onComplete) => {
Velocity(blockRef.current, {
translateX: toX,
translateY: toY,
complete: () => {
onComplete();
}
},
{
duration: duration
});
}
const moveNorth = () => {
setDirection('North');
console.log('Moving N: ', direction);
move(0, 0, 500, () => {
decideDirection();
})
}
const moveEast = () => {
setDirection('East');
console.log('Moving E: ', direction);
move(500, 0, 2500, () => {
decideDirection();
})
};
const moveSouth = () => {
setDirection('South');
console.log('Moving S: ', direction);
move(500, 18, 500, () => {
decideDirection();
})
}
const moveWest = () => {
setDirection('West');
console.log('Moving W: ', direction);
move(0, 18, 2500, () => {
decideDirection();
})
}
return(
<div>
<div id='block' onClick={onClick} ref={blockRef} style={{ width: '100px', height: '18px', backgroundColor: 'red', textAlign: 'center'}}>{direction}</div>
</div>
);
};
ReactDOM.render(<div><Example/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
I find this kind of strange because none of these functions are memoized so they should re-create every render and thus have the new value. Even if I do add something like useCallback
and provide direction
to every function it still won't work. Why don't the functions know about the updated version of the state var?