digamos que tenemos los componentes como este
const Example = () => { const [counter, setCounter] = useState(0); const increment = () => setCounter(counter => counter + 1); return ( <div> <Button onClick={increment} /> <div>{counter}</div> </div> ); } Cuando pasé el controlador onClick como una función de flecha , mi eslint lanzó una advertencia:
error JSX props should not use arrow functions react/jsx-no-bindComo leí en una respuesta de esta publicación: https://stackoverflow.com/questions/36677733/why-shouldnt-jsx-props-use-arrow-functions-or-bind#:~:text=Why%20you%20shouldn 't%20uso,%20función%20anterior%20es%20basura%20recolectada .
La respuesta corta es porque la función de flecha se recrea cada vez, lo que perjudicará el rendimiento. Una solución propuesta a partir de esta publicación es envolverse en un enlace useCallback , con una matriz vacía. Y cuando cambio a esto, la advertencia de eslint realmente desaparece.
const Example = () => { const [counter, setCounter] = useState(0); const increment = useCallback(() => setCounter(counter => counter + 1), []); return ( <div> <Button onClick={increment} /> <div>{counter}</div> </div> ); }Sin embargo, también hay otra opinión que dice que el uso excesivo de useCallback eventualmente ralentizará el rendimiento debido a los gastos generales de useCallback. Un ejemplo está aquí: https://kentcdodds.com/blog/usememo-and-usecallback
¿Esto me está confundiendo mucho? Entonces, para los componentes funcionales, cuando se trata de un controlador de funciones en línea, ¿debería simplemente escribir la función de flecha (ignorar el eslint) o siempre envolverla en un useCallback?
En mi opinión, useCallback no es para el rendimiento. No puedo pensar en ninguna razón por la que definir una función sea realmente costoso. A diferencia de useMemo , useCallback simplemente memoriza la función y no la ejecuta.
Entonces, ¿cuándo debemos usarlo?
El caso de uso principal es evitar volver a ejecutar una función innecesariamente. Redefinir una función no es problemático, pero volver a ejecutarla en cada actualización de estado tiene errores y, a menudo, es peligroso.
useCallback cuando la función deba estar dentro de la matriz de dependencia de useEffectHay dos casos en los que puedo pensar en este momento:
const [data, setData] = useState([]); const [filter, setFilter] = useState({}); const fetchData = useCallback(async () => { const response = await fetchApi(filter); setData(response.data); }, [filter]); useEffect(() => { fetchData(); }, [fetchData]); (Si la función no es asíncrona, podemos usar useEffect directamente sin usar useCallback )
Sin embargo, no es necesario envolverlo con useCallback cuando solo se ejecuta mediante la interacción del usuario:
const [data, setData] = useState([]); const [filter, setFilter] = useState({}); const fetchData = async () => { const response = await fetchApi(filter); setData(response.data); }; return ( <button onClick={fetchData}>Fetch Data</button> ); const onAwesomeLibarayLoaded = useCallback(() => { doSomething(state1, state2); }, [state1, state2]); <AwesomeLibrary onLoad={onAwesomeLibarayLoaded} /> Porque el componente AwesomeLibrary podría hacer algo como el ejemplo 1 con la función onLoad pasada:
const AwesomeLibarary = ({onLoad}) => { useEffect(() => { // do something onLoad(); }, [onLoad]); }; Si está seguro de que no está dentro useEffect , entonces está bien, incluso si no usa useCallback .