web-dev-qa-db-fra.com

Comment mettre à jour un élément dans List avec ImmutableJS?

Voici ce que la documentation officielle a dit

updateIn(keyPath: Array<any>, updater: (value: any) => any): List<T>
updateIn(keyPath: Array<any>, notSetValue: any, updater: (value: any) => any): List<T>
updateIn(keyPath: Iterable<any, any>, updater: (value: any) => any): List<T>
updateIn(keyPath: Iterable<any, any>, notSetValue: any, updater: (value: any) => any): List<T>

Il n’ya aucun moyen pour un développeur web normal (programmeur non fonctionnel) de comprendre cela!

J'ai assez simple (pour l'approche non-fonctionnelle) cas.

var arr = [];
arr.Push({id: 1, name: "first", count: 2});
arr.Push({id: 2, name: "second", count: 1});
arr.Push({id: 3, name: "third", count: 2});
arr.Push({id: 4, name: "fourth", count: 1});
var list = Immutable.List.of(arr);

Comment puis-je mettre à jour list où l'élément avec le nom troisième a son compte défini sur 4?

124
Vitalii Korsakov

Le cas le plus approprié consiste à utiliser les deux méthodes findIndex et update.

list = list.update(
  list.findIndex(function(item) { 
    return item.get("name") === "third"; 
  }), function(item) {
    return item.set("count", 4);
  }
); 

P.S. Il n'est pas toujours possible d'utiliser Maps. Par exemple. si les noms ne sont pas uniques et que je souhaite mettre à jour tous les éléments portant le même nom.

115
Vitalii Korsakov

Avec . SetIn () vous pouvez faire la même chose:

let obj = fromJS({
  elem: [
    {id: 1, name: "first", count: 2},
    {id: 2, name: "second", count: 1},
    {id: 3, name: "third", count: 2},
    {id: 4, name: "fourth", count: 1}
  ]
});

obj = obj.setIn(['elem', 3, 'count'], 4);

Si nous ne connaissons pas l’index de l’entrée que nous voulons mettre à jour. Il est assez facile de le trouver en utilisant . FindIndex () :

const indexOfListToUpdate = obj.get('elem').findIndex(listItem => {
  return listItem.get('name') === 'third';
});
obj = obj.setIn(['elem', indexOfListingToUpdate, 'count'], 4);

J'espère que ça aide!

29
Albert Olivé

Voici ce que la documentation officielle a dit… updateIn

Vous n'avez pas besoin de updateIn, qui ne concerne que les structures imbriquées. Vous recherchez la méthode update , qui comporte une signature et une documentation beaucoup plus simples:

Renvoie une nouvelle liste avec une valeur mise à jour à index avec la valeur de retour du programme de mise à jour appelant avec la valeur existante, ou notSetValue si l'index n'a pas été défini.

update(index: number, updater: (value: T) => T): List<T>
update(index: number, notSetValue: T, updater: (value: T) => T): List<T>

qui, comme le suggère Map::update docs , est " équivalent à: list.set(index, updater(list.get(index, notSetValue)))".

où élément avec le nom "troisième"

Ce n'est pas comme ça que les listes fonctionnent. Vous devez connaître l'index de l'élément que vous souhaitez mettre à jour ou vous devez le rechercher.

Comment puis-je mettre à jour la liste où l'élément avec le nom troisième a son compte défini sur 4?

Cela devrait le faire:

list = list.update(2, function(v) {
    return {id: v.id, name: v.name, count: 4};
});
18
Bergi
var index = list.findIndex(item => item.name === "three")
list = list.setIn([index, "count"], 4)

Explication

La mise à jour des collections Immutable.js renvoie toujours les nouvelles versions de ces collections en laissant l'original inchangé. Pour cette raison, nous ne pouvons pas utiliser la syntaxe de mutation list[2].count = 4 de JavaScript. Au lieu de cela, nous devons appeler des méthodes, comme nous pourrions le faire avec les classes de collection Java.

Commençons par un exemple plus simple: juste les comptes dans une liste.

var arr = [];
arr.Push(2);
arr.Push(1);
arr.Push(2);
arr.Push(1);
var counts = Immutable.List.of(arr);

Maintenant, si nous voulions mettre à jour le troisième élément, un tableau JS simple pourrait ressembler à ceci: counts[2] = 4. Puisque nous ne pouvons pas utiliser mutation et que nous devons appeler une méthode, nous pouvons utiliser: counts.set(2, 4) - cela signifie que vous définissez la valeur 4 à l'index 2.

Mises à jour approfondies

L'exemple que vous avez donné contient des données imbriquées. Nous ne pouvons pas simplement utiliser set() sur la collection initiale.

Les collections Immutable.js ont une famille de méthodes dont les noms se terminent par "In", ce qui vous permet d'apporter des modifications plus profondes dans un jeu imbriqué. Les méthodes de mise à jour les plus courantes ont une méthode "In" associée. Par exemple, pour set, il y a setIn. Au lieu d'accepter un index ou une clé comme premier argument, ces méthodes "In" acceptent un "chemin d'accès à la clé". Le chemin d'accès à la clé est un tableau d'index ou de clés qui illustre comment obtenir la valeur que vous souhaitez mettre à jour.

Dans votre exemple, vous vouliez mettre à jour l'élément de la liste à l'index 2, puis la valeur de la clé "count" dans cet élément. Donc, le chemin clé serait [2, "count"]. Le second paramètre de la méthode setIn fonctionne exactement comme set, c'est la nouvelle valeur que nous voulons y mettre, donc:

list = list.setIn([2, "count"], 4)

Trouver le bon chemin de clé

En allant un peu plus loin, vous avez en fait indiqué vouloir mettre à jour l'élément où le nom est "trois" , ce qui est différent du troisième élément. Par exemple, peut-être que votre liste n'est pas triée ou peut-être que l'élément nommé "deux" a été supprimé plus tôt? Cela signifie d’abord que nous devons nous assurer de connaître le bon chemin de clé! Pour cela, nous pouvons utiliser la méthode findIndex() (qui, d'ailleurs, fonctionne presque exactement comme Array # findIndex ).

Une fois que nous avons trouvé l'index dans la liste contenant l'élément que nous souhaitons mettre à jour, nous pouvons fournir le chemin d'accès à la valeur que nous souhaitons mettre à jour:

var index = list.findIndex(item => item.name === "three")
list = list.setIn([index, "count"], 4)

NB: Set vs Update

La question initiale mentionne les méthodes de mise à jour plutôt que les méthodes définies. Je vais expliquer le deuxième argument de cette fonction (appelé updater), car il est différent de set(). Alors que le second argument de set() est la nouvelle valeur que nous voulons, le second argument de update() est une fonction qui accepte la valeur précédente et renvoie la nouvelle valeur que nous voulons. Alors, updateIn() est la variante "In" de update() qui accepte un chemin de clé.

Supposons par exemple que nous voulions une variante de votre exemple qui ne se contente pas de définir le compte sur 4, mais qui incrémente le nombre existant , ajoute un à la valeur existante:

var index = list.findIndex(item => item.name === "three")
list = list.updateIn([index, "count"], value => value + 1)
16
Lee Byron

Utilisez . Map ()

list = list.map(item => 
   item.get("name") === "third" ? item.set("count", 4) : item
);
var arr = [];
arr.Push({id: 1, name: "first", count: 2});
arr.Push({id: 2, name: "second", count: 1});
arr.Push({id: 3, name: "third", count: 2});
arr.Push({id: 4, name: "fourth", count: 1});
var list = Immutable.fromJS(arr);

var newList = list.map(function(item) {
    if(item.get("name") === "third") {
      return item.set("count", 4);
    } else {
      return item;
    }
});

console.log('newList', newList.toJS());

// More succinctly, using ES2015:
var newList2 = list.map(item => 
    item.get("name") === "third" ? item.set("count", 4) : item
);

console.log('newList2', newList2.toJS());
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>
9
Meistro

J'aime beaucoup cette approche du site thomastuts :

const book = fromJS({
  title: 'Harry Potter & The Goblet of Fire',
  isbn: '0439139600',
  series: 'Harry Potter',
  author: {
    firstName: 'J.K.',
    lastName: 'Rowling'
  },
  genres: [
    'Crime',
    'Fiction',
    'Adventure',
  ],
  storeListings: [
    {storeId: 'Amazon', price: 7.95},
    {storeId: 'barnesnoble', price: 7.95},
    {storeId: 'biblio', price: 4.99},
    {storeId: 'bookdepository', price: 11.88},
  ]
});

const indexOfListingToUpdate = book.get('storeListings').findIndex(listing => {
  return listing.get('storeId') === 'Amazon';
});

const updatedBookState = book.setIn(['storeListings', indexOfListingToUpdate, 'price'], 6.80);

return state.set('book', updatedBookState);
0
Dryden Williams