Los Hooks son una adición brillante a React. Simplifican mucha lógica que anteriormente tenía que dividirse en diferentes ciclos de vida con class
componentes.
Sin embargo, requieren un modelo mental diferente , especialmente para los principiantes.
También grabé una breve serie de videos sobre este artículo que puede resultarle útil.
Rebote y aceleración
Hay un montón de publicaciones de blog escritas sobre antirrebote y aceleración, así que no me sumergiré en cómo escribir tu propio antirrebote y aceleración. Por brevedad, considere debounce
y throttle
de Lodash.
Si necesita un repaso rápido, ambos aceptan una función (devolución de llamada) y un retraso en milisegundos (digamos x
) y luego ambos devuelven otra función con algún comportamiento especial:
debounce
: Devuelve una función que se puede llamar cualquier número de veces (posiblemente en sucesiones rápidas), pero sólo se invocar la devolución de llamada después de esperar durantex
ms de la última llamada.throttle
: devuelve una función que se puede llamar cualquier número de veces (posiblemente en una sucesión rápida) pero solo invocará la devolución de llamada como máximo una vez cadax
ms.
Caso de uso
Tenemos un editor de blog mínimo (aquí está el repositorio de GitHub) y nos gustaría guardar la publicación del blog en la base de datos 1 segundo después de que el usuario deja de escribir.
También puede consultar este cuadro de códigos si desea ver la versión final del código.
Una versión mínima de nuestro editor se ve así:
import React, { useState } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally const handleChange = event => { setValue(event.target.value); }; return ( Blog
Editor (Client)
{value} Saved (DB)
{dbValue} ); }
Aquí, en saveToDb
realidad sería una llamada API al backend. Para simplificar las cosas, lo guardo en estado y luego lo renderizo como dbValue
.
Dado que solo queremos realizar esta operación de guardado una vez que el usuario haya dejado de escribir (después de 1 segundo), esto debe eliminarse .
Aquí está el repositorio y la rama del código de inicio.
Creando una función antirrebote
En primer lugar, necesitamos una función antirrebote que envuelva la llamada a saveToDb
:
import React, { useState } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally const handleChange = event => { const { value: nextValue } = event.target; setValue(nextValue); // highlight-starts const debouncedSave = debounce(() => saveToDb(nextValue), 1000); debouncedSave(); // highlight-ends }; return {/* Same as before */}; }
Pero, esto en realidad no funciona porque la función debouncedSave
se crea nueva en cada handleChange
llamada. Esto terminará eliminando cada pulsación de tecla en lugar de eliminar todo el valor de entrada.
useCallback
useCallback
se usa comúnmente para optimizar el rendimiento al pasar devoluciones de llamada a componentes secundarios. Pero podemos usar su restricción de memorizar una función de devolución de llamada para asegurar que las debouncedSave
referencias tengan la misma función antirrebote en todas las representaciones.
También escribí este artículo aquí en freeCodeCamp si desea comprender los conceptos básicos de la memorización.
Esto funciona como se esperaba:
import React, { useState, useCallback } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally // highlight-starts const debouncedSave = useCallback( debounce(nextValue => saveToDb(nextValue), 1000), [], // will be created only once initially ); // highlight-ends const handleChange = event => { const { value: nextValue } = event.target; setValue(nextValue); // Even though handleChange is created on each render and executed // it references the same debouncedSave that was created initially debouncedSave(nextValue); }; return {/* Same as before */}; }
useRef
useRef
nos da un objeto mutable cuya current
propiedad se refiere al valor inicial pasado. Si no lo cambiamos manualmente, el valor persistirá durante toda la vida útil del componente.
Esto es similar a las propiedades de instancia de clase (es decir, definir métodos y propiedades en this
).
Esto también funciona como se esperaba:
import React, { useState, useRef } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally // This remains same across renders // highlight-starts const debouncedSave = useRef(debounce(nextValue => saveToDb(nextValue), 1000)) .current; // highlight-ends const handleChange = event => { const { value: nextValue } = event.target; setValue(nextValue); // Even though handleChange is created on each render and executed // it references the same debouncedSave that was created initially debouncedSave(nextValue); }; return {/* Same as before */}; }
Continúe leyendo en mi blog sobre cómo abstraer estos conceptos en ganchos personalizados o consulte la serie de videos.
You may also follow me on Twitter to stay updated on my latest posts. I hope you found this post helpful. :)