You're probably best off using CSS transforms or a module such as react-spring, but if neither of them suit you then you want requestAnimationFrame
.
(CSS Transforms can make text blurry CSS transition effect makes image blurry / moves image 1px, in Chrome? and for a one-off you might not want the bundle load of an external module)
https://codesandbox.io/s/pj9m554nkj
const animate = ({ timing, draw, duration }) => {
let start = performance.now();
const animateLoop = time => {
const durationFraction = Math.min(
1,
Math.max(0, (time - start) / duration)
);
const progress = timing(durationFraction);
draw(progress);
if (durationFraction < 1) {
requestAnimationFrame(animateLoop);
}
};
requestAnimationFrame(animateLoop);
};
const MovingDiv = ({ move, duration }) => {
const [pos, setPos] = useState(0);
useEffect(() => {
animate({
timing: fraction => move * fraction,
draw: progress => setPos(progress),
duration
});
}, []);
return <div className="MovingDiv" style={{ left: pos }} />;
};
You can also then start playing with easeIn/easeOut in the timing function to add a bit of spring.. https://codesandbox.io/s/2w6ww8oymp