Tengo dos estados definidos así:
const [productProperties, setProductProperties] = useState< PropertyGroup[] | null >(null); const [originalProductProperties, setOriginalProductProperties] = useState< PropertyGroup[] | null >(null); Se supone que el primero se actualiza a través de la entrada del usuario y el segundo se usa más tarde para una comparación, de modo que solo los PropertyGroup que han cambiado los valores se enviarán a través de la API para que se actualicen.
He hecho esto miles de veces antes, pero por alguna razón cuando cambio el valor del name de un PropertyGroup y actualizo el estado de 'productProperties' así:
(e, itemId) => { const update = [...productProperties]; const i = update.findIndex((group) => group.id === itemId); if (i !== -1) { update[i].name = { ...update[i].name, [selectedLocale]: e.currentTarget.value, }; setProductProperties([...update]); } } El estado de originalProductProperties también se actualiza. ¿Por qué? setOriginalProductProperties nunca se llama aquí, tampoco estoy mutando ningún estado directamente y uso el operador de propagación para asegurarme de crear nuevas referencias. Estoy perdido.
Prefacio: parece que las dos matrices comparten los mismos objetos. Eso está bien siempre que maneje las actualizaciones correctamente.
Aunque está copiando la matriz , está modificando el objeto en la matriz directamente. Eso está rompiendo la regla principal del estado: No modificar el estado directamente
En su lugar, haga una copia del objeto también:
(e, itemId) => { const update = [...productProperties]; const i = update.findIndex((group) => group.id === itemId); if (i !== -1) { update[i] = { // *** Note making a new object ...update[i], [selectedLocale]: e.currentTarget.value, };; setProductProperties(update); // (No need to *re*copy the array here, you've already done it at the top of the function) } } O, dado que tiene esa verificación i !== -1 allí, podríamos copiar la matriz más tarde para que no la copiemos si no encontramos el grupo que coincide con itemId :
(e, itemId) => { const i = productProperties.findIndex((group) => group.id === itemId); if (i !== -1) { const update = [...productProperties]; update[i] = { // *** Note making a new object ...update[i], [selectedLocale]: e.currentTarget.value, };; setProductProperties(update); } } FWIW, en los casos en los que sabe que habrá una coincidencia, el map es bueno para esto (pero probablemente no en este caso, ya que parece indicar que el grupo puede no estar allí):
(e, itemId) => { const update = productProperties.map((group) => { if (group.id === itemId) { // It's the one we want, create the replacement group = { ...group, [selectedLocale]: e.currentTarget.value, }; } return group; }); setProductProperties(update); }O a veces lo ves escrito con un operador condicional:
(e, itemId) => { const update = productProperties.map((group) => group.id === itemId ? { // It's the one we want, create a replacement ...group, [selectedLocale]: e.currentTarget.value, } : group ); setProductProperties(update); }