Se siente como cualquier tipo de acción de "hacer clic y arrastrar" que creo se siente un poco ... bueno, entrecortado. Como si estuviera tartamudeando. Sé que cuando registro en la consola, los datos son instantáneos desde el evento, pero los retrasos en la actualización del estado son los que hacen que parezca más lento.
Aquí hay un ejemplo muy simple:
const TestMouseOver = () => { const [pos, setPos] = useState(); const onMouseDown = (e) => { setPos({ x: e.clientX + document.body.scrollLeft, y: e.clientY + document.body.scrollTop, }) } const onMouseMove = (e) => { setPos({ x: e.clientX + document.body.scrollLeft, y: e.clientY + document.body.scrollTop, }) } return ( <div onMouseDown={(event) => onMouseDown(event)} onMouseMove={(event) => onMouseMove(event)} onMouseUp={() => setPos(null)} > {pos && <MoveBox position={pos} />} </div> ); }; dentro de MoveBox , tomo la pos y simplemente configuro el css absoluto del div como la posición (componentes con estilo). Nada de lujos allí. Funciona pero es lento y lento.
¿Debería intentar crear algún tipo de lerp o animación para ir al último cable conocido para suavizar la actualización de posición?
MouseEvents no están limitados: cada vez que se mueva el mouse, llamará a sus funciones setState . Eso puede suceder cientos de veces por segundo, lo que hace que React se vuelva a renderizar con tanta frecuencia, lo que es mucho menos óptimo.
Con el tempo máximo, React no debería renderizar más de cada fotograma de 16 ms para garantizar animaciones fluidas de 60 FPS en su sitio web.
Debe acelerar estos eventos usando lodash.throttle por ejemplo y registrar una devolución de llamada usando useCallback .
Código de muestra :
const handleMouseMove = useCallback(lodash.throttle((e) => { setPos({ x: e.clientX + document.body.scrollLeft, y: e.clientY + document.body.scrollTop, }); }, 16), []); return ( <div onMouseMove={handleMouseMove}>{...}</div> ) Observe el 16 como el segundo argumento de lodash.throttle : garantiza que la función no se llame con más frecuencia que cada 16 ms.
Otro posible enfoque que debe considerar sería usar una solicitud de api nativa del navegadorAnimationFrame
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
Así se implementaría para tu caso específico
const TestMouseOver = () => { const [pos, setPos] = useState(); let ticking = false; function onMouseMove(event) { requestTick(event); } function onMouseDown(event) { requestTick(event); } function requestTick(event) { if (!ticking) { requestAnimationFrame(update(event)); } ticking = true; } function update(e) { // reset the tick so we can capture next mouseevent ticking = false; setPos((prevState) => ({ x: e.clientX + document.body.scrollLeft, y: e.clientY + document.body.scrollTop, })) } return ( <div onMouseDown={(event) => onMouseDown(event)} onMouseMove={(event) => onMouseMove(event)} onMouseUp={() => setPos(null)} > {pos && <MoveBox position={pos} />} </div> ); };PROS:
CONTRAS:
Cómo funciona: básicamente, usando una variable y el método requestAnimationFrame, nos aseguramos de que el estado se actualice a la velocidad de actualización del cuadro.