Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

293
Vistas
Reaccionar useEffect Hook cuando solo cambia una de las deps del efecto, pero no las otras

Tengo un componente funcional usando Hooks:

 function Component(props) { const [ items, setItems ] = useState([]); // In a callback Hook to prevent unnecessary re-renders const handleFetchItems = useCallback(() => { fetchItemsFromApi().then(setItems); }, []); // Fetch items on mount useEffect(() => { handleFetchItems(); }, []); // I want this effect to run only when 'props.itemId' changes, // not when 'items' changes useEffect(() => { if (items) { const item = items.find(item => item.id === props.itemId); console.log("Item changed to " item.name); } }, [ items, props.itemId ]) // Clicking the button should NOT log anything to console return ( <Button onClick={handleFetchItems}>Fetch items</Button> ); }

El componente obtiene algunos items en el montaje y los guarda en el estado.

El componente recibe una propiedad itemId (de React Router).

Siempre que cambie props.itemId , quiero que esto active un efecto, en este caso, registrándolo en la consola.


El problema es que, dado que el efecto también depende de los items , el efecto también se ejecutará cada vez que cambien los items , por ejemplo, cuando items vuelvan a recuperar presionando el botón.

Esto se puede solucionar almacenando el props.itemId anterior en una variable de estado separada y comparando los dos, pero esto parece un truco y agrega repetitivo. Usando clases de componentes, esto se resuelve comparando accesorios actuales y anteriores en componentDidUpdate , pero esto no es posible usando componentes funcionales, que es un requisito para usar Hooks.


¿Cuál es la mejor manera de activar un efecto que depende de múltiples parámetros, solo cuando uno de los parámetros cambia?


PD. Los ganchos son algo nuevo, y creo que todos estamos haciendo todo lo posible para descubrir cómo trabajar correctamente con ellos, así que si mi forma de pensar sobre esto te parece incorrecta o incómoda, indícalo.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

El equipo de React dice que la mejor manera de obtener valores previos es usar useRef: https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state

 function Component(props) { const [ items, setItems ] = useState([]); const prevItemIdRef = useRef(); useEffect(() => { prevItemIdRef.current = props.itemId; }); const prevItemId = prevItemIdRef.current; // In a callback Hook to prevent unnecessary re-renders const handleFetchItems = useCallback(() => { fetchItemsFromApi().then(setItems); }, []); // Fetch items on mount useEffect(() => { handleFetchItems(); }, []); // I want this effect to run only when 'props.itemId' changes, // not when 'items' changes useEffect(() => { if(prevItemId !== props.itemId) { console.log('diff itemId'); } if (items) { const item = items.find(item => item.id === props.itemId); console.log("Item changed to " item.name); } }, [ items, props.itemId ]) // Clicking the button should NOT log anything to console return ( <Button onClick={handleFetchItems}>Fetch items</Button> ); }

Creo que esto podría ayudar en tu caso.

Nota: si no necesita el valor anterior, otro enfoque es escribir un useEffect más para props.itemId

 React.useEffect(() => { console.log('track changes for itemId'); }, [props.itemId]);
over 4 years ago · Santiago Trujillo Denunciar

0

Una salida fácil es escribir un enlace personalizado para ayudarnos con eso.

 // Desired hook function useCompare (val) { const prevVal = usePrevious(val) return prevVal !== val } // Helper hook function usePrevious(value) { const ref = useRef(); useEffect(() => { ref.current = value; }); return ref.current; }

y luego usarlo en useEffect

 function Component(props) { const hasItemIdChanged = useCompare(props.itemId); useEffect(() => { if(hasItemIdChanged) { // … } }, [props.itemId, hasItemIdChanged]) return <></> }
over 4 years ago · Santiago Trujillo Denunciar

0

⚠️ NOTA : esta respuesta actualmente es incorrecta y podría generar errores/efectos secundarios inesperados. La variable useCallback tendría que ser una dependencia del gancho useEffect , lo que conduciría al mismo problema al que se enfrentaba OP.

lo abordaré lo antes posible

Recientemente me encontré con esto en un proyecto, y nuestra solución fue mover el contenido de useEffect a una devolución de llamada (memorizada en este caso) y ajustar las dependencias de ambos. Con su código proporcionado se ve algo como esto:

 function Component(props) { const [ items, setItems ] = useState([]); const onItemIdChange = useCallback(() => { if (items) { const item = items.find(item => item.id === props.itemId); console.log("Item changed to " item.name); } }, [items, props.itemId]); // I want this effect to run only when 'props.itemId' changes, // not when 'items' changes useEffect(onItemIdChange, [ props.itemId ]); // Clicking the button should NOT log anything to console return ( <Button onClick={handleFetchItems}>Fetch items</Button> ); }

Entonces, useEffect solo tiene el ID prop como su dependencia, y la devolución de llamada tanto los elementos como el ID.

De hecho, podría eliminar la dependencia de ID de la devolución de llamada y pasarla como un parámetro a la devolución de llamada onItemIdChange :

 const onItemIdChange = useCallback((id) => { if (items) { const item = items.find(item => item.id === id); console.log("Item changed to " item.name); } }, [items]); useEffect(() => { onItemIdChange(props.itemId) }, [ props.itemId ])
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda