490 votes

Mise à jour d'un objet avec setState dans React

Est-il possible de mettre à jour les propriétés d'un objet à l'aide de la fonction setState ?

Quelque chose comme :

this.state = {
   jasper: { name: 'jasper', age: 28 },
}

J'ai essayé :

this.setState({jasper.name: 'someOtherName'});

et ceci :

this.setState({jasper: {name: 'someothername'}})

La première entraîne une erreur de syntaxe et la seconde ne fait rien. Avez-vous une idée ?

12 votes

Le deuxième code aurait fonctionné mais vous auriez perdu le age propriété à l'intérieur jasper .

1 votes

Je comprends que React utilise .assign() pour. fusionner l'ancien objet d'état avec le nouvel objet, donc le second code ne devrait-il pas fonctionner correctement ?

1040voto

Mayank Shukla Points 39317

Il existe de multiples façons de procéder, puisque la mise à jour de l'état est une opération asynchrone donc pour mettre à jour l'objet d'état, nous devons utiliser fonction de mise à jour avec setState .

1- La plus simple :

Créez d'abord une copie de jasper puis faire les changements dans ce domaine :

this.setState(prevState => {
  let jasper = Object.assign({}, prevState.jasper);  // creating copy of state variable jasper
  jasper.name = 'someothername';                     // update the name property, assign a new value                 
  return { jasper };                                 // return new object jasper object
})

Au lieu d'utiliser Object.assign on peut aussi l'écrire comme ceci :

let jasper = { ...prevState.jasper };

2- Utilisation syntaxe de l'étalement :

this.setState(prevState => ({
    jasper: {                   // object that we want to update
        ...prevState.jasper,    // keep all other key-value pairs
        name: 'something'       // update the value of specific key
    }
}))

Note : Object.assign et Spread Operator crée uniquement copie superficielle Par conséquent, si vous avez défini des objets ou des tableaux d'objets imbriqués, vous devez adopter une approche différente.


Mise à jour de l'objet d'état imbriqué :

Supposons que vous ayez défini l'état comme :

this.state = {
  food: {
    sandwich: {
      capsicum: true,
      crackers: true,
      mayonnaise: true
    },
    pizza: {
      jalapeno: true,
      extraCheese: false
    }
  }
}

Pour mettre à jour l'extraCheese de l'objet pizza :

this.setState(prevState => ({
  food: {
    ...prevState.food,           // copy all other key-value pairs of food object
    pizza: {                     // specific object of food object
      ...prevState.food.pizza,   // copy all pizza key-value pairs
      extraCheese: true          // update value of specific key
    }
  }
}))

Mise à jour d'un tableau d'objets :

Supposons que vous ayez une application de tâches à faire, et que vous gériez les données dans ce formulaire :

this.state = {
  todoItems: [
    {
      name: 'Learn React Basics',
      status: 'pending'
    }, {
      name: 'Check Codebase',
      status: 'pending'
    }
  ]
}

Pour mettre à jour le statut de n'importe quel objet à faire, exécutez une carte sur le tableau et vérifiez la valeur unique de chaque objet, dans le cas de condition=true retourne le nouvel objet avec la valeur mise à jour, sinon le même objet.

let key = 2;
this.setState(prevState => ({

  todoItems: prevState.todoItems.map(
    el => el.key === key? { ...el, status: 'done' }: el
  )

}))

Suggestion : Si l'objet n'a pas de valeur unique, il faut utiliser l'index du tableau.

0 votes

La méthode que j'essayais de mettre en place fonctionne cependant... la deuxième méthode :S

11 votes

@JohnSnow dans la seconde, il supprimera les autres propriétés de la base de données. jasper l'objet, faites le console.log(jasper) vous ne verrez qu'une seule clé name l'âge n'y sera pas :)

0 votes

Vrai... La façon que vous avez décrite est-elle la SEULE façon de procéder... étant donné que je veux utiliser React et non Redux ?

81voto

mannok Points 381

C'est le moyen le plus rapide et le plus lisible :

this.setState({...this.state.jasper, name: 'someothername'});

Même si this.state.jasper contient déjà une propriété de nom, le nouveau nom name: 'someothername' avec être utilisé.

74 votes

Cette solution présente un gros inconvénient : afin d'optimiser les mises à jour d'état, React peut regrouper plusieurs mises à jour. En conséquence this.state.jasper ne contient pas nécessairement le dernier état. Il vaut mieux utiliser la notation avec le prevState .

41voto

Nikhil Points 160

Utilisez l'opérateur d'étalement et un peu d'ES6 ici

this.setState({
    jasper: {
          ...this.state.jasper,
          name: 'something'
    }
})

8 votes

Cela met à jour jasper mais les autres propriétés sont supprimées de l'état.

13voto

Alberto Piras Points 111

J'ai utilisé cette solution.

Si vous avez un état imbriqué comme ceci :

this.state = {
  formInputs:{
    friendName:{
      value:'',
      isValid:false,
      errorMsg:''
    },
    friendEmail:{
      value:'',
      isValid:false,
      errorMsg:''
    }
  }
}

vous pouvez déclarer la fonction handleChange qui copie l'état actuel et le réaffecte avec les valeurs modifiées

handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let statusCopy = Object.assign({}, this.state);
    statusCopy.formInputs[inputName].value = inputValue;

    this.setState(statusCopy);
  }

ici le html avec l'écouteur d'événement. Assurez-vous d'utiliser le même nom que celui utilisé dans l'objet d'état (dans ce cas, 'friendName').

<input type="text" onChange={this.handleChange} " name="friendName" />

0 votes

Cela a fonctionné pour moi, sauf que j'ai dû utiliser ceci à la place : statusCopy.formInputs[inputName] = inputValue;

11voto

Burak Kahraman Points 51

Essayez ceci, cela devrait fonctionner correctement

this.setState(Object.assign(this.state.jasper,{name:'someOtherName'}));

9 votes

Vous modifiez l'objet d'état directement. Pour utiliser cette approche, ajoutez un nouvel objet comme source : Object.assign({}, this.state.jasper, {name:'someOtherName'})

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X