Digamos que tengo una matriz como esta:
[ { country: '', 'city/province': '', street: '' }, { country: '', 'city/province': '', street: '' } ] ¿Cómo hago para que se ejecute el gancho useEffect() cada vez que cambia el valor del campo 'país' en cualquier elemento dentro de la matriz?
Normalmente, no querría hacer eso, pero solo para responder a su pregunta, se puede hacer, así que permítame proponer lo siguiente, suponiendo que su lista se llame items :
useEffect(() => { }, [...items.map(v => v.country)]) Lo que hace el código anterior es distribuir todos los items (con su propiedad de country ) en la matriz de dependencia useEffect .
La razón por la que esto puede ser ad hoc es principalmente porque a React no le gusta tener una dependencia de longitud variable. En el código fuente, cuando cambia la longitud, solo aprecia el cambio de elemento de los elementos existentes. Por lo tanto, podría tener problemas si cambia de 1 elemento a 2 elementos.
Sin embargo, si tiene un número fijo de elementos, esto debería hacer lo que quería. Tenga en cuenta que los items deben ser una matriz en todo momento.
NOTA: para acomodar el problema de la longitud, tal vez podamos agregar una length variable adicional a la matriz de dependencias :)
}, [items.length, ...items.map(v => v.country)]) Como mencioné, la mayoría de las veces, debe evitar hacer esto, en su lugar, intente cambiar los items completos cada vez que cambie un elemento. Y deje que el Item se muestre para optimizar, como React.memo .
No creo que pueda abordarlo específicamente en la matriz de dependencia, sin embargo, puede hacer su verificación dentro de useEffect para obtener el mismo resultado general.
Básicamente, a la matriz de dependencia se le pasa el estado de datos completo, lo que activará el efecto con cada cambio, luego realiza una verificación adicional si la subpropiedad ha cambiado.
Estoy aprovechando lodash por brevedad, pero puede ejecutar cualquier función para determinar si los datos han cambiado.
Codepen: https://codepen.io/chrisk7777/pen/mdMvpvo?editors=0010
const { useState, useEffect, useRef } = React; const { render } = ReactDOM; const { isEqual, map } = _; const App = () => { const [data, setData] = useState([ { country: "", "city/province": "", street: "" }, { country: "", "city/province": "", street: "" } ]); const prevData = useRef(data); // hacky updates just to demonstrate the change // change country - should trigger useEffect const update1 = () => { setData((s) => [s[0], { ...s[1], country: s[1].country + "a" }]); }; // change street - should not trigger useEffect const update2 = () => { setData((s) => [s[0], { ...s[1], street: s[1].street + "a" }]); }; useEffect(() => { if (!isEqual(map(prevData.current, "country"), map(data, "country"))) { console.log("country changed"); } prevData.current = data; }, [data]); return ( <div> <button onClick={update1}>change country - trigger effect</button> <br /> <button onClick={update2}>change street - do not trigger effect</button> </div> ); }; render(<App />, document.getElementById("app"));Simplemente mapee los países en la matriz de dependencia de efectos.
const countries = data.map((x) => x.country); useEffect(() => { console.log(countries); }, countries);