web-dev-qa-db-fra.com

Suppression d'un élément d'un tableau dans l'état du composant

J'essaie de trouver le meilleur moyen de supprimer un élément d'un tableau dans l'état d'un composant. Comme je ne devrais pas modifier directement la variable this.state, existe-t-il un meilleur moyen (plus concis) de supprimer un élément d'un tableau que ce que j'ai ici ?:

  onRemovePerson: function(index) {
    this.setState(prevState => { // pass callback in setState to avoid race condition
      let newData = prevState.data.slice() //copy array from prevState
      newData.splice(index, 1) // remove element
      return {data: newData} // update state
    })
  },

Je vous remercie.

mis à jour

Cela a été mis à jour pour utiliser le rappel dans setState. Cela devrait être fait lors de la référence à l'état actuel lors de sa mise à jour.

124
aherriot

La façon la plus propre de faire ce que j'ai vu est avec filter:

removeItem(index) {
  this.setState({
    data: this.state.data.filter((_, i) => i !== index)
  });
}
124
ephrion

Vous pouvez utiliser l'auxiliaire d'aide à l'immutabilité update() DE _react-addons-update , qui fait la même chose sous le capot, mais ce que vous faites est bien.

_this.setState(prevState => ({
  data: update(prevState.data, {$splice: [[index, 1]]})
}))
_
87
Jonny Buchanan

Je crois que le référencement de this.state à l'intérieur de setState() est déconseillé ( les mises à jour d'état peuvent être asynchrones ).

Les docs recommandent d'utiliser setState() avec une fonction de rappel afin que prevState soit transmis au moment de l'exécution lorsque la mise à jour se produit. Donc, voici à quoi cela ressemblerait:

Utilisation de Array.prototype.filter sans ES6

removeItem : function(index) {
  this.setState(function(prevState){
    return { data : prevState.data.filter(function(val, i) {
      return i !== index;
    })};
  });
}

Utilisation de Array.prototype.filter avec les fonctions de flèche ES6

removeItem(index) {
  this.setState((prevState) => ({
    data: prevState.data.filter((_, i) => i !== index)
  }));
}

Utilisation de immutability-helper

import update from 'immutability-helper'
...
removeItem(index) {
  this.setState((prevState) => ({
    data: update(prevState.data, {$splice: [[index, 1]]})
  }))
}

Utilisation de Spread

function removeItem(index) {
  this.setState((prevState) => ({
    data: [...prevState.data.slice(0,index), ...prevState.data.slice(index+1)]
  }))
}

Notez que dans chaque instance, quelle que soit la technique utilisée, this.setState() reçoit un rappel, et non une référence d'objet à l'ancien this.state;

59
pscl

Voici un moyen de supprimer l'élément du tableau dans l'état à l'aide de la syntaxe d'étalement ES6.

onRemovePerson: (index) => {
  const data = this.state.data;
  this.setState({ 
    data: [...data.slice(0,index), ...data.slice(index+1)]
  });
}
23
evianpring

Je veux parler ici même si cette question a déjà été répondu correctement par @pscl au cas où quelqu'un d'autre rencontrerait le même problème que moi. Parmi les 4 méthodes, j'ai choisi d'utiliser la syntaxe es6 avec les fonctions de flèche en raison de sa concision et de son manque de dépendance vis-à-vis des bibliothèques externes:

Utilisation de Array.prototype.filter avec les fonctions de flèche ES6

removeItem(index) {
  this.setState((prevState) => ({
    data: prevState.data.filter((_, i) => i != index)
  }));
}

Comme vous pouvez le constater, j'ai légèrement modifié le type d'index (!== à !=) car, dans mon cas, je récupérais l'index dans un champ de chaîne.

Un autre point utile si vous observez un comportement étrange lors de la suppression d'un élément côté client est de NE JAMAIS utiliser l'index d'un tableau comme clé de l'élément :

// bad
{content.map((content, index) =>
  <p key={index}>{content.Content}</p>
)}

Lorsque React diffère avec le DOM virtuel lors d'une modification, il examinera les clés pour déterminer ce qui a changé. Donc, si vous utilisez des index et qu'il y en a un de moins dans le tableau, le dernier sera supprimé. À la place, utilisez les identifiants du contenu comme clés, comme ceci.

// good
{content.map(content =>
  <p key={content.id}>{content.Content}</p>
)}

Ce qui précède est un extrait de cette réponse d'un article connexe .

Bon codage à tous!

3
c0d3ster

Comme mentionné dans un commentaire sur la réponse de ephrion ci-dessus, filter () peut être lent, en particulier avec les grands tableaux, car il effectue une boucle pour rechercher un index qui semble avoir déjà été déterminé. C'est une solution propre mais inefficace.

En guise d'alternative, vous pouvez simplement "découper" l'élément souhaité et concaténer les fragments.

var dummyArray = [];    
this.setState({data: dummyArray.concat(this.state.data.slice(0, index), this.state.data.slice(index))})

J'espère que cela t'aides!

1
Matt Ellis

Vous pouvez utiliser cette fonction si vous souhaitez supprimer l'élément (sans index)

removeItem(item) {
  this.setState(prevState => {
    data: prevState.data.filter(i => i !== item)
  });
}
1
julian libor

Vous pouvez rendre le code plus lisible avec une fonction d'assistance à une ligne:

const removeElement = (arr, i) => [...arr.slice(0, i), ...arr.slice(i+1)];

puis utilisez-le comme ceci:

this.setState(state => ({ places: removeElement(state.places, index) }));
0
Brian Burns