Escuché que declarar una función en un componente de reacción para manejar los clics debe hacerse dentro de un enlace useCallback para evitar recrear la función en cada renderizado, especialmente si la función es algo compleja, como esta:
const handleClick = useCallback(()=> { "...do a lot of calculations here that takes time" },[]); <button onClick={handleClick}> Click me! </button>
Pero tengo un caso especial en el que quiero que la función useCallback se active cuando se hace clic en el botón para establecer un estado, esto es lo que quiero:
const [state, setState] = useState(); const handleClick = useCallback(()=> { const newState = "...do a lot of calculations here that takes time" setState( newState ) },[ when button is clicked ]);
El problema es, ¿cómo coloco el "cuando se hace clic en el botón" en la dependencia de useCallback y, de hecho, cualquier gancho de reacción que acepte una lista de dependencias? Podría hacerlo con alguna variable tonta y separando los cálculos costosos que toman tiempo de la función onClick, como se muestra a continuación, pero no creo que sea un buen enfoque ya que estaré desperdiciando memoria:
const [state, setState] = useState(); const [dumb, setDumb] = useState(0); useEffect(()=> { const newState = "...do a lot of calculations here that takes time" setState( newState ) },[ dumb ]); <button onClick=()=>setDumb(dumb+1)> Click me! </button>
Creo que lo tienes un poco al revés. El useCallback
realmente solo es útil si la función memorizada devuelta se transmite al componente descendiente a través de accesorios. El beneficio no es que la función sea pesada y algunos cálculos estén optimizados, sino que la referencia de devolución de llamada es estable y no activará una representación innecesaria de un componente secundario.
En cuanto al uso de una función como controlador onClick
de un botón, es el valor de retorno del useCallback
el que se pasa al controlador onClick
del botón, no al revés, donde intenta hacer que el evento de clic sea la dependencia.
Ejemplo:
const clickHandler = useCallback(() => { // do some expensive computations }, [...dependencies]); ... <button type="button" onClick={clickHander}>Click Me</button>
Si no está pasando clickHandler
como accesorio a otro componente de React, no hay mucho beneficio en memorizarlo.
El ejemplo de código setDumb
es un caso de uso en el que usar el useEffect
sería más apropiado, el efecto es ejecutar el código complejo/pesado cuando se actualiza la dependencia del estado dumb
.
Es más simple simplemente poner la lógica compleja/pesada en una devolución de llamada regular y poner en cola una actualización de estado normal cuando se completa. Solo use useCallback
si pasa esta función como accesorio a otro componente de React.
El problema es, ¿cómo pongo el "cuando se hace clic en el botón" en la dependencia de useCallback?
No lo hace: las dependencias deben ser exactamente (y solo) el estado/accesorios a los que se hace referencia dentro de la función.
Por ejemplo, si la función fuera
() => { setCountState(countState + 1); setToggledState(!toggledState); }
entonces la matriz de dependencias debería ser
[setCountState, countState, setToggledState, toggledState]
La regla ESLint exhaustive-deps le ayuda a automatizar esto.
Para su situación, está perfectamente bien tener lo anterior como las únicas dependencias: no desea un valor de marcador de posición "tonto" ni ninguna otra dependencia en la matriz de dependencia.
Todo lo que dijo:
la declaración de una función en un componente de reacción para manejar los clics debe hacerse dentro de un enlace useCallback para evitar recrear la función en cada renderizado, especialmente si la función es algo compleja
Este no es realmente el caso. useCallback
no es necesario ni útil en el 99% de las situaciones a menos que la función se transfiera a otros componentes, según mi experiencia, lo que no parece ser el caso aquí. (La función se volverá a crear cada renderizado independientemente).
useCallback
brilla cuando hay otros componentes que usan una función (especialmente componentes que no conoce) y desea transmitirles una referencia lo más estable posible, para evitar repeticiones innecesarias y llamadas gancho.
useCallback
no impide la creación de la función. Solo le impide tener una nueva referencia de función cada vez que vuelve a renderizar. Entonces, con useCallback
, la función se vuelve a crear cada renderizado, compre useCallback
le devuelve una referencia anterior de una función anterior si ninguna de las dependencias enumeradas se ha actualizado.
Desea crear el controlador de clics, agregar todas las dependencias que usa (setState, etc.) y luego usar el controlador en un detector de eventos como onClick de un botón.
const Comp = () => { const [state, setState] = useState([]); const clickHandler = useCallback((ev) => { setState(prevState => prevState.concat([/* something */]) }, [setState]); return <button onClick={clickHandler}>Button</button> }