La siguiente aplicación React muestra una lista de frutas. Cada Fruit tiene un botón "agregar a favoritos" que usa una devolución de llamada addFav para agregar dicha fruta a una lista de favoritos en el padre. Pasar la devolución de llamada handleAddFav provoca repeticiones innecesarias, por lo que lo envolví en useCallback y Fruit in memo .
Sin embargo, useCallback exige tener favs en su matriz de dependencia, lo que hace que handleAddFav se vuelva a calcular cada vez que se llama. Esto anula el propósito de usar useCallback para detener las re-renderizaciones porque ahora cada Fruit se re-renderiza cada vez que agregas un favorito. ¿Como puedo resolver esto?
import { useState, memo, useCallback } from "react"; import "./styles.css"; const Fruit = memo(({title, id, addFav}) => { console.log(title, 'rendered') return ( <div> <div>{title}</div> <button onClick={() => addFav(title, id)}>add fav</button> </div> ) }) export default function App() { const [favs, setFavs] = useState([]) const data = [{title: 'apple', id: '1'}, {title:'orange', id:'2'} , {title:'banana', id:'3'}] const handleAddFav = useCallback((title, id) => { setFavs([...favs, {title, id}]) }, [favs]) return ( <div className="App"> <h1>Testing useCallback that sets an array</h1> <h2>Favorites</h2> <button onClick={() => setFavs([])}>clear</button> { favs.map(({title, id}, i) => <span key={id + i}>{title}</span>) } { data.map(({title, id }) => ( <Fruit key={id} title={title} id={id} addFav={handleAddFav}/> )) } </div> ); }Una forma es usar la versión de función de setFavs en su lugar, para que no dependa de una variable externa.
const handleAddFav = useCallback((title, id) => { setFavs(favs => [...favs, {title, id}]) }, []) Para la situación más general, incluso si tuviera un valor que tuviera que volver a calcularse, el uso de useCallback aún podría reducir las repeticiones para los casos en los que cambian otros valores en el componente, pero no el valor calculado. Por ejemplo
const TheComponent = () => { const [toggled, setToggled] = useState(false); const [num, setNum] = useState(5); const cb = useCallback(() => { // imagine that this does something that depends on num }, [num]); Si se transmite cb , aunque dependa de num , useCallback seguirá evitando que los niños se vuelvan a renderizar en el caso de que solo se cambie toggled y num permanezca igual.