Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

291
Views
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 answers
Answer question

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!