v19.2Latest

Mettre à jour les tableaux dans l'état

Les tableaux sont mutables en JavaScript, mais vous devez les traiter comme immuables lorsque vous les stockez dans l'état. Tout comme pour les objets, lorsque vous souhaitez mettre à jour un tableau stocké dans l'état, vous devez en créer un nouveau (ou faire une copie d'un tableau existant), puis définir l'état pour utiliser le nouveau tableau.

Vous apprendrez
  • Comment ajouter, supprimer ou modifier des éléments dans un tableau de l'état React
  • Comment mettre à jour un objet à l'intérieur d'un tableau
  • Comment rendre la copie de tableaux moins répétitive avec Immer

Mettre à jour les tableaux sans mutation

En JavaScript, les tableaux sont simplement un autre type d'objet.Comme pour les objets,vous devez traiter les tableaux dans l'état React comme étant en lecture seule.Cela signifie que vous ne devez pas réaffecter d'éléments à l'intérieur d'un tableau commearr[0] = 'bird', et vous ne devez pas non plus utiliser de méthodes qui mutent le tableau, telles quepush()etpop().

Au lieu de cela, chaque fois que vous souhaitez mettre à jour un tableau, vous devrez passer unnouveautableau à votre fonction de définition d'état. Pour ce faire, vous pouvez créer un nouveau tableau à partir du tableau d'origine dans votre état en appelant ses méthodes non mutantes commefilter()etmap(). Ensuite, vous pouvez définir votre état sur le nouveau tableau résultant.

Voici un tableau de référence des opérations courantes sur les tableaux. Lorsque vous manipulez des tableaux à l'intérieur de l'état React, vous devrez éviter les méthodes de la colonne de gauche et préférer les méthodes de la colonne de droite :

à éviter (mute le tableau)à préférer (renvoie un nouveau tableau)
ajoutpush,unshiftconcat,[...arr]syntaxe de décomposition (exemple)
suppressionpop,shift,splicefilter,slice(exemple)
remplacementsplice,arr[i] = ...assignationmap(exemple)
trireverse,sortcopier le tableau d'abord (exemple)

Alternativement, vous pouvezutiliser Immerqui vous permet d'utiliser des méthodes des deux colonnes.

Piège

Malheureusement,sliceetspliceont des noms similaires mais sont très différents :

  • slicevous permet de copier un tableau ou une partie de celui-ci.
  • splicemutele tableau (pour insérer ou supprimer des éléments).

Dans React, vous utiliserezslice(sansp!) beaucoup plus souvent car vous ne voulez pas muter les objets ou tableaux dans l'état.Mettre à jour les objetsexplique ce qu'est la mutation et pourquoi elle n'est pas recommandée pour l'état.

Ajouter à un tableau

push()mutera un tableau, ce que vous ne voulez pas :

Créez plutôt unnouveautableau qui contient les éléments existantsetun nouvel élément à la fin. Il existe plusieurs façons de faire cela, mais la plus simple est d'utiliser la syntaxe de...propagation de tableau :

Maintenant, cela fonctionne correctement :

La syntaxe de propagation de tableau vous permet également d'ajouter un élément au début en le plaçantavant le ...artistsd'origine :

De cette façon, la propagation peut remplir le rôle depush()en ajoutant à la fin d'un tableau et deunshift()en ajoutant au début d'un tableau. Essayez-le dans le bac à sable ci-dessus !

Supprimer d'un tableau

La façon la plus simple de supprimer un élément d'un tableau est dele filtrer. En d'autres termes, vous allez produire un nouveau tableau qui ne contiendra pas cet élément. Pour cela, utilisez la méthodefilter, par exemple :

Cliquez quelques fois sur le bouton « Supprimer » et observez son gestionnaire de clic.

Ici,artists.filter(a => a.id !== artist.id)signifie « créer un tableau composé desartistsdont les ID sont différents deartist.id». En d'autres termes, le bouton « Supprimer » de chaque artiste va filtrercetartiste du tableau, puis demander un nouveau rendu avec le tableau résultant. Notez quefilterne modifie pas le tableau d'origine.

Transformer un tableau

Si vous souhaitez modifier certains ou tous les éléments du tableau, vous pouvez utilisermap()pour créer unnouveautableau. La fonction que vous passerez àmappeut décider quoi faire avec chaque élément, en fonction de ses données ou de son index (ou des deux).

Dans cet exemple, un tableau contient les coordonnées de deux cercles et d'un carré. Lorsque vous appuyez sur le bouton, il déplace uniquement les cercles de 50 pixels vers le bas. Il le fait en produisant un nouveau tableau de données à l'aide demap():

Remplacer des éléments dans un tableau

Il est particulièrement courant de vouloir remplacer un ou plusieurs éléments dans un tableau. Des affectations commearr[0] = 'bird'mutent le tableau d'origine, donc vous devrez plutôt utilisermappour cela également.

Pour remplacer un élément, créez un nouveau tableau avecmap. Dans votre appel àmap, vous recevrez l'index de l'élément comme second argument. Utilisez-le pour décider si vous retournez l'élément d'origine (le premier argument) ou autre chose :

Insertion dans un tableau

Parfois, vous pouvez vouloir insérer un élément à une position particulière qui n'est ni au début ni à la fin. Pour ce faire, vous pouvez utiliser la syntaxe de décomposition de tableau...conjointement avec la méthodeslice(). La méthodeslice()vous permet de découper une « tranche » du tableau. Pour insérer un élément, vous allez créer un tableau qui décompose la trancheavantle point d'insertion, puis le nouvel élément, et enfin le reste du tableau d'origine.

Dans cet exemple, le bouton Insertion insère toujours à l'index1:

Apporter d'autres modifications à un tableau

Il y a certaines choses que vous ne pouvez pas faire uniquement avec la syntaxe de décomposition et les méthodes non mutantes commemap()etfilter(). Par exemple, vous pouvez vouloir inverser ou trier un tableau. Les méthodes JavaScriptreverse()etsort()mutent le tableau d'origine, donc vous ne pouvez pas les utiliser directement.

Cependant, vous pouvez d'abord copier le tableau, puis y apporter des modifications.

Par exemple :

Ici, vous utilisez la syntaxe de décomposition[...list]pour d'abord créer une copie du tableau d'origine. Maintenant que vous avez une copie, vous pouvez utiliser des méthodes mutantes commenextList.reverse()ounextList.sort(), ou même assigner des éléments individuels avecnextList[0] = "something".

Cependant,même si vous copiez un tableau, vous ne pouvez pas muter directement les éléments existantsà l'intérieurde celui-ci.En effet, la copie est superficielle — le nouveau tableau contiendra les mêmes éléments que l'original. Donc, si vous modifiez un objet à l'intérieur du tableau copié, vous mutez l'état existant. Par exemple, un code comme celui-ci pose problème.

Bien quenextListetlistsoient deux tableaux différents,nextList[0]etlist[0]pointent vers le même objet.Ainsi, en modifiantnextList[0].seen, vous modifiez égalementlist[0].seen. Il s'agit d'une mutation d'état, que vous devez éviter ! Vous pouvez résoudre ce problème d'une manière similaire à lamise à jour d'objets JavaScript imbriqués— en copiant les éléments individuels que vous souhaitez modifier au lieu de les muter. Voici comment faire.

Mise à jour d'objets à l'intérieur de tableaux

Les objets ne sont pasréellementsitués « à l'intérieur » des tableaux. Ils peuvent sembler être « à l'intérieur » dans le code, mais chaque objet d'un tableau est une valeur distincte, vers laquelle le tableau « pointe ». C'est pourquoi vous devez être prudent lorsque vous modifiez des champs imbriqués commelist[0]. La liste d'œuvres d'art d'une autre personne peut pointer vers le même élément du tableau !

Lors de la mise à jour d'un état imbriqué, vous devez créer des copies à partir du point où vous souhaitez mettre à jour, et ce jusqu'au niveau supérieur.Voyons comment cela fonctionne.

Dans cet exemple, deux listes d'œuvres d'art distinctes ont le même état initial. Elles sont censées être isolées, mais à cause d'une mutation, leur état est accidentellement partagé, et cocher une case dans une liste affecte l'autre liste :

Le problème se trouve dans un code comme celui-ci :

Bien que le tableaumyNextListsoit nouveau,les éléments eux-mêmessont les mêmes que dans le tableau originalmyList. Ainsi, modifierartwork.seenmodifie l'élément artworkoriginal. Cet élément artwork se trouve également dansyourList, ce qui provoque le bug. Ces bugs peuvent être difficiles à conceptualiser, mais heureusement, ils disparaissent si vous évitez de muter l'état.

Vous pouvez utilisermappour remplacer un ancien élément par sa version mise à jour sans mutation.

Ici,...est la syntaxe de décomposition d'objet utilisée pourcréer une copie d'un objet.

Avec cette approche, aucun des éléments d'état existants n'est muté, et le bug est corrigé :

En général,vous ne devez muter que les objets que vous venez de créer.Si vous insérez une œuvre d'artnouvelle, vous pouvez la muter, mais si vous manipulez quelque chose qui est déjà dans l'état, vous devez en faire une copie.

Écrire une logique de mise à jour concise avec Immer

La mise à jour de tableaux imbriqués sans mutation peut devenir un peu répétitive.Tout comme pour les objets:

  • En général, vous ne devriez pas avoir besoin de mettre à jour l'état à plus de quelques niveaux de profondeur. Si vos objets d'état sont très profonds, vous pourriez vouloirles restructurer différemmentpour qu'ils soient plats.
  • Si vous ne souhaitez pas modifier la structure de votre état, vous pourriez préférer utiliserImmer, qui vous permet d'écrire avec une syntaxe pratique mais mutante et se charge de produire les copies pour vous.

Voici l'exemple de la liste de souhaits artistiques réécrit avec Immer :

Notez qu'avec Immer,une mutation commeartwork.seen = nextSeenest désormais acceptable :

C'est parce que vous ne modifiez pas l'étatoriginal, mais vous modifiez un objet spécialdraftfourni par Immer. De même, vous pouvez appliquer des méthodes de mutation commepush()etpop()au contenu dudraft.

En arrière-plan, Immer construit toujours le prochain état à partir de zéro selon les modifications que vous avez apportées audraft. Cela permet de garder vos gestionnaires d'événements très concis sans jamais muter l'état.

Récapitulatif

  • Vous pouvez placer des tableaux dans l'état, mais vous ne pouvez pas les modifier.
  • Au lieu de muter un tableau, créez unenouvelleversion de celui-ci et mettez à jour l'état avec celle-ci.
  • Vous pouvez utiliser la syntaxe de décomposition de tableau[...arr, newItem]pour créer des tableaux avec de nouveaux éléments.
  • Vous pouvez utiliserfilter()etmap()pour créer de nouveaux tableaux avec des éléments filtrés ou transformés.
  • Vous pouvez utiliser Immer pour garder votre code concis.

Try out some challenges

Challenge 1 of 4:Update an item in the shopping cart #

Fill in the handleIncreaseClick logic so that pressing ”+” increases the corresponding number: