2 votes

L'état du tableau React continue de se réinitialiser lors d'une mise à jour dans un composant fonctionnel

J'ai créé un composant React avec un tableau d'état. state.colors qui contient trois valeurs hexagonales (l'état initial est ['#aaaaaa', '#aaaaaa', '#aaaaaa'] ). Chaque valeur de la state.colors peut être mis à jour à l'aide de sélecteurs de couleur. À titre de test, j'ai mis à jour la première couleur en rouge, la deuxième en vert et la troisième en bleu. Cela fonctionne comme prévu dans un composant de classe (comme le montre la capture d'écran ci-dessous).

class EditArtworkClass extends React.Component {
  constructor(props) {
    this.state = {
      colors: initialPalette
    };
  }

  setColor(index, hex) {
    const clonedColors = _.clone(this.state.colors);
    clonedColors[index] = hex;

    this.setState(
      {
        colors: clonedColors
      },
      () => {
        console.log("updated");
      }
    );
  }

  // other code here
}

Composante de classe - Avant de choisir les couleurs :

Class component before updates

Composant de classe - Après avoir choisi les couleurs ( state.colors ont les valeurs hexagonales correctes) :

Class component after updates

Cependant, je suis confronté à un problème lorsque j'utilise un composant fonctionnel. Chaque fois que je mets à jour une couleur à l'aide du sélecteur de couleur, toutes les autres valeurs du composant fonctionnel colors sont réinitialisés à la valeur initiale ( #aaaaaa ). Si je règle la première couleur sur le rouge, la deuxième sur le bleu et la troisième sur le vert, seule la dernière valeur dans le champ colors aura le bon hexagone puisque les deux autres valeurs sont remises à zéro. #aaaaaa lors de la mise à jour de la troisième couleur.

export default function EditArtworkFunctional() {
  const [colors, setColors] = useState(initialPalette);

  const setColor = (index, hex) => {
    const clonedColors = _.clone(colors);
    clonedColors[index] = hex;

    return clonedColors;
  };

  // Other code here
}

Composant fonctionnel - Avant de choisir les couleurs :

Functional component before updates

Composante fonctionnelle - Après avoir choisi les couleurs (seule la dernière couleur que je choisis a un hexagone correct dans l'état) :

Functional component after updates

Notez que le sélecteur de couleur est un composant non contrôlé et qu'il affichera les couleurs que vous choisissez, et non pas la couleur de l'écran de l'utilisateur. colors tableau d'état.

J'ai créé une mini-application reproductible dans le cadre du programme Lien vers Codesandbox ci-dessous.

App.js

Lien Condesandbox : https://codesandbox.io/s/class-vs-functional-component-array-state-8lnzd

Je n'ai aucune idée de la raison pour laquelle cela se produit, donc toute aide ou conseil serait grandement apprécié.

UPDATE : J'ai résolu le problème en utilisant la réponse de @TalOrlanczyk. L'astuce était de récupérer l'état précédent en utilisant le paramètre optionnel lors de la mise à jour. Vous pouvez voir le CodeSandbox repo de la version de travail ici .

4voto

theWellHopeErr Points 1679

Cela est dû à deux raisons

  1. const clonedColors = _.clone(colors) en utilisant ce clone profond du tableau, ce qui n'est pas ce que nous voulons, nous devons faire une copie superficielle du tableau. Donc, const clonedColors = colors sera le bon chemin.
  2. setColors(clonedColors) ne fonctionne pas correctement, mais si nous setState en utilisant la syntaxe de l'étalement setColors([...clonedColors]) il le fera. C'est parce que le tableau est juste une référence, et React setState ne se rendra pas si l'état ne reçoit pas une nouvelle référence. C'est pourquoi nous envoyons une nouvelle référence de tableau en utilisant la syntaxe de propagation [...clonedColors] . Merci à @TalOrlanczyk pour la raison.

    const setColor = (index, color) => { const clonedColors = colors; clonedColors[index] = color; setColors([...clonedColors]); console.log(colors); };

Voici le Lien Codesandbox mis à jour

3voto

TalOrlanczyk Points 786

Je pense avoir résolu le problème

const setColor = (index, hex) => {
    setColors((prev) => {
      console.log(prev);
      const clonedColors = [...prev];
      clonedColors[index] = hex;
      return clonedColors;
    });
  };

comme @theWellHopeErr le dit, c'est parce que cela s'est produit parce que vous ne l'avez pas envoyé comme un opérateur d'étalement. c'est arrivé parce que le tableau est une référence si vous changez la même référence c'est peut-être changer la valeur mais l'état d'utilisation ne l'attrape pas parce que ce n'est pas une nouvelle référence.

Une autre chose que vous devriez savoir est qu'il est bien mieux d'utiliser la méthode comme ceci (avec le prev) parce que de cette façon vous pouvez être sûr d'obtenir la dernière entrée réelle que vous avez insérée dans cet état.

UPDATE

L'opérateur d'étalement n'est bon que pour les objets peu profonds ; quand il s'agit d'un objet profond comme les objets avec une propriété avec un objet, cela ne fonctionnera pas et changera l'état original également.

ne modifie pas l'état actuel, c'est un anti-modèle dans React. Voici un fil de discussion qui l'explique parfaitement

Cloner un tableau pour faire un clone profond, vous devez utiliser

un bon article dans un média qui explique ce qu'est un clone superficiel et profond.

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