He revisado un par de artículos sobre useCallback y useMemo sobre cuándo usar y cuándo no usar, pero en su mayoría he visto código muy contrived . Estaba mirando un código en mi empresa donde noté que alguien había hecho esto:
const takePhoto = useCallback(() => { launchCamera({ mediaType: "photo", cameraType: "front" }, onPickImage); }, []); const pickPhotoFromLibrary = async () => { launchImageLibrary({ mediaType: "photo" }, onPickImage); } const onUploadPress = useCallback(() => { Alert.alert( "Upload Photo", "From where would you like to take your photo?", [ { text: "Camera", onPress: () => takePhoto() }, { text: "Library", onPress: () => pickPhotoFromLibrary() }, ] ); }, [pickPhotoFromLibrary, takePhoto]);Así se llama onUploadPress:
<TouchableOpacity style={styles.retakeButton} onPress={onUploadPress} > ¿Crees que esta es la forma correcta de llamarlo? Según mi comprensión de esos artículos, esto parece incorrecto. ¿Alguien puede decirme cuándo usar useCallback y quizás también explicar useCallback en términos más humanos?
Artículo que leí: https://kentcdodds.com/blog/usememo-and-usecallback .
useCallback devuelve una función JavaScript normal, con respecto a cómo usarla. Es la misma función que la que obtiene como primer parámetro respecto a lo que hace. Aunque la función devuelta se memoriza. Lo que significa que cuando su componente se vuelve a renderizar, React no recreará esa función (que es el comportamiento de una función normal dentro de un componente).
React recreará una nueva versión de esa función si cambia una de las variables dentro de la matriz (el segundo parámetro de useCallback ). Vale la pena si lo pasa a un componente que está memorizado con React.memo (algo que hacer si ese componente hace muchos cálculos o es muy pesado).
Un componente memorizado se volverá a renderizar solo si cambia su state o props . Y debido a que normalmente se crea una nueva versión de esa función pasada cuando el padre vuelve a renderizar, el componente secundario obtiene una nueva referencia de esa función, por lo que se vuelve a renderizar. Es por eso que a veces se usa useCallback para memorizar la función pasada.
En su caso, usar useCallback para onUploadPress es una pérdida de rendimiento, pickPhotoFromLibrary , una función no memorizada está en la matriz de dependencia. Es una pérdida de rendimiento también porque TouchableOpacity no se memoriza con React.memo .
Memoizar no es gratis. Memorizar mal es peor que no memorizar nada. Aquí está el recurso más completo y más corto que he visto para comprender en profundidad, el proceso de renderizado de React para saber cuándo memorizar y cuándo no: React Render Tutorial .
En palabras simples, useCallback se usa para guardar la referencia de la función en algún lugar fuera del renderizado del componente para que podamos usar la misma referencia nuevamente. Esa referencia se cambiará cada vez que cambie una de las variables en la matriz de dependencias. Como sabe, React intenta minimizar el proceso de renderizado observando los cambios de valor de algunas variables, luego decide volver a renderizar sin depender del valor anterior y el valor nuevo de esas variables. Por lo tanto, el uso básico de useCallback es mantener el valor anterior y el valor nuevo por igual.
Intentaré demostrarlo más dando algunos ejemplos en situaciones en las que debemos usar useCalback .
useEffect . function Component(){ const [state, setState] = useState() // Should use `useCallback` function handleChange(input){ setState(...) } useEffect(()=>{ handleChange(...) },[handleChange]) return ... }useEffect , conduce a un bucle infinito. function Parent(){ const [state, setState] = useState() function handleChange(input){ setState(...) } return <Child onChange={handleChange} /> } function Child({onChange}){ const [state, setState] = useState() useEffect(()=>{ onChange(...) },[onChange]) return "Child" }React Context que contiene un estado y devuelve solo las funciones de establecimiento de estado, necesita que el consumidor de ese context no vuelva a procesar cada vez que se actualice el estado, ya que puede dañar el rendimiento. const Context = React.createContext(); function ContextProvider({children}){ const [state, setState] = useState([]); // Should use `useCallback` const addToState = (input) => { setState(prev => [...prev, input]); } // Should use `useCallback` const removeFromState = (input) => { setState(prev => prev.filter(elem => elem.id !== input.id)); } // Should use `useCallback` with empty [] const getState = () => { return state; } const contextValue= React.useMemo( () => ({ addToState , removeFromState , getState}), [addToState , removeFromState , getState] ); // if we used `useCallback`, our contextValue will never change and all the subscribers will not re-render <Context.Provider value={contextValue}> {children} </Context.Provider> }Ejemplo 4: si está suscrito al observador, el temporizador, los eventos del documento y necesita darse de baja cuando el componente se desmonta o por cualquier otro motivo. Entonces, necesitamos acceder a la misma referencia para cancelar la suscripción.
function Component(){ // should use `useCallback` const handler = () => {...} useEffect(() => { element.addEventListener(eventType, handler) return () => element.removeEventListener(eventType, handler) }, [eventType, element]) return ... } Eso es todo, hay múltiples situaciones en las que también puede usarlo, pero espero que estos ejemplos demuestren la idea principal detrás de useCallback . Y recuerde siempre que no necesita usarlo si el costo del renderizado es insignificante.