0
votes

Impossible de définir l'état avec le hook useState avec l'appel de fonction

J'ai défini mon objet d'état initial comme ceci:

 const Double = e => {
        SetItem(Item.foodNutrients.forEach(foodNutrient => foodNutrient.value *= 2))
        console.log(Item)
    }

Je souhaite modifier mon objet existant en effectuant une boucle sur le tableau foodNutrient et en doublant la valeur en cliquant sur le bouton, puis en stockant l'objet mis à jour dans le hook useState.

const [Item,SetItem] = useState(
        {
            description: "Chicken",
            foodNutrients:[
            {nutrientName: "Protein", nutrientNumber: "203", value: 10},
            {nutrientName: "Fat", nutrientNumber: "204",  value: 15},
            {nutrientName: "Carbs", nutrientNumber: "205", value: 20}
            ]
        }
    )

il enregistre le résultat correct sur la console la première fois que j'essaye de cliquer sur <button onClick={Double}>Set state</button> , mais la deuxième fois, il lance Cannot read property 'foodNutrients' of undefined et je ne peux rien rendre.


1 commentaires

L'état React est généralement supposé être immuable, il devrait être immuable en cas de hook useState . Cela signifie qu'il devrait y avoir un nouvel objet lorsqu'un état est changé


3 Réponses :


1
votes

La logique de votre gestionnaire d'événements remplace l'objet initial par undefined car Array.prototype.forEach renvoie undefined par défaut.

Ce que vous devez faire est:

  1. map vers un tableau avec de nouvelles valeurs
  2. conserver l'état précédent et définir la valeur du tableau dans l'état sur le nouveau tableau mappé
const Double = (e) => {
  const foodNutrientsNew = Item.foodNutrients.map((foodNutrient) => ({
    ...foodNutrient,
    value: foodNutrient.value * 2,
  }));
  SetItem((prev) => ({ ...prev, foodNutrients: foodNutrientsNew }));
};

MISE À JOUR

Je suggérerais également de refactoriser votre code et de le diviser en plusieurs composants. Suivez simplement l'article officiel de la documentation ici


1 commentaires

@EstusFlask est d'accord. fixé



0
votes

Une bien meilleure approche consiste à le faire dans le gestionnaire onClick à la place -

 const Double = e => {

    // clone your Item object
    const cloneItem = {...Item};

    // now make modifications in the new object
    cloneItem.foodNutrients.forEach(foodNutrient => foodNutrient.value *=2 );      
     
    SetItem(cloneItem);

    // to see the difference in console
    console.log(cloneItem)
    console.log(Item)
}


0 commentaires

0
votes

J'ai essayé beaucoup de choses pour vous aider et j'ai trouvé cette solution qui fonctionne pour moi.

function App() {
  const [item, setItem] = useState({
    description: "Chicken",
    foodNutrients: [
      { nutrientName: "Protein", nutrientNumber: "203", value: 10 },
      { nutrientName: "Fat", nutrientNumber: "204", value: 15 },
      { nutrientName: "Carbs", nutrientNumber: "205", value: 20 },
    ],
  });

  console.log(item);

  const double = (e) => {
    setItem({...item}, item.foodNutrients.map(e => e.value *=2));
  }
  return <button onClick={double}>Set state</button>;
}


0 commentaires