web-dev-qa-db-fra.com

réagir Hooks useState Array

J'ai essayé de rechercher la réinitialisation des valeurs de tableau useState ici, mais je n'ai trouvé aucune référence aux valeurs de tableau.

Essayer de changer la valeur de la liste déroulante de l'état initial aux valeurs allowedState. J'utilise la méthode des crochets ici pour définir les valeurs avec - setStateValues. Si je commente cette ligne de code, elle affiche le menu déroulant. Je ne comprenais pas pourquoi je ne pouvais pas utiliser la méthode setStateValues ​​pour réinitialiser les valeurs des variables d'état.

Je reçois le message d'erreur suivant: "Trop de rediffusions. React limite le nombre de rendus pour empêcher une boucle infinie".

S'il vous plaît aider si vous voyez quelque chose de mal ici. Je vais continuer à chercher.

    import React, { useState } from "react"; 
    import ReactDOM from "react-dom";

    const StateSelector = () => {   
    const initialValue = [
    { id: 0,value: " --- Select a State ---" }];

      const allowedState = [
        { id: 1, value: "Alabama" },
        { id: 2, value: "Georgia" },
        { id: 3, value: "Tennessee" }
        ];

      const [stateOptions, setStateValues] = useState(initialValue);  
      // initialValue.Push(...allowedState);

      console.log(initialValue.length);

      setStateValues(allowedState); // Not sure why cannot I reset the state in here for an array.

         return (<div>
          <label>Select a State:</label>
          <select>
            {stateOptions.map((localState, index) => (
              <option key={localState.id}>{localState.value}</option>
            ))}
          </select>
        </div>   ); };

    const rootElement = document.getElementById("root");
    ReactDOM.render(<StateSelector />, rootElement);
8
shavi

Vous ne devez pas définir d'état (ou faire autre chose avec des effets secondaires) depuis la fonction de rendu. Lorsque vous utilisez des hooks, vous pouvez utiliser useEffect pour cela.

La version suivante fonctionne:

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

const StateSelector = () => {
  const initialValue = [
    { id: 0, value: " --- Select a State ---" }];

  const allowedState = [
    { id: 1, value: "Alabama" },
    { id: 2, value: "Georgia" },
    { id: 3, value: "Tennessee" }
  ];

  const [stateOptions, setStateValues] = useState(initialValue);
  // initialValue.Push(...allowedState);

  console.log(initialValue.length);
  // ****** BEGINNING OF CHANGE ******
  useEffect(() => {
    // Should not ever set state during rendering, so do this in useEffect instead.
    setStateValues(allowedState);
  }, []);
  // ****** END OF CHANGE ******

  return (<div>
    <label>Select a State:</label>
    <select>
      {stateOptions.map((localState, index) => (
        <option key={localState.id}>{localState.value}</option>
      ))}
    </select>
  </div>);
};

const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);

et ici dans un sandbox de code .

Je suppose que vous souhaitez éventuellement charger la liste d'états à partir d'une source dynamique (sinon, vous pouvez simplement utiliser allowedState directement sans utiliser useState du tout). Si tel est le cas, cet appel api pour charger la liste pourrait également aller dans le bloc useEffect.

10
Ryan Cogswell

Pour développer la réponse de Ryan:

Chaque fois que setStateValues ​​est appelée, React rend à nouveau votre composant, ce qui signifie que le corps de la fonction StateSelector du composant est ré-exécuté.

Réagir docs :

setState () mènera toujours à une restitution à moins que shouldComponentUpdate () ne renvoie false.

Essentiellement, vous définissez l'état avec:

setStateValues(allowedState);

provoquant un re-rendu, ce qui entraîne l'exécution de la fonction, etc. D'où le problème de la boucle.

Pour illustrer ce point, si vous définissez un délai d’attente comme suit:

  setTimeout(
    () => setStateValues(allowedState),
    1000
  )

Ce qui termine le problème de "trop de reprises".

Dans votre cas, vous faites face à un effet secondaire, qui est traité avec UseEffect dans les fonctions de votre composant. Vous pouvez en lire plus à ce sujet ici .

2
Joel H

Essayez de garder votre état minimal. Il n'y a pas besoin de stocker

   const initialValue = [
    { id: 0,value: " --- Select a State ---" }];

comme état. Séparer le permanent du changeant

const ALL_STATE_VALS = [
    { id: 0,value: " --- Select a State ---" }
    { id: 1, value: "Alabama" },
    { id: 2, value: "Georgia" },
    { id: 3, value: "Tennessee" }
];

Ensuite, vous pouvez stocker uniquement l'identifiant en tant qu'état:

const StateSelector = () =>{
  const [selectedStateOption, setselectedStateOption] = useState(0);

  return (
    <div>
      <label>Select a State:</label>
      <select>
        {ALL_STATE_VALS.map((option, index) => (
          <option key={option.id} selected={index===selectedStateOption}>{option.value}</option>
        ))}
      </select>
    </div>);
   )
}
1
Ben Carp

La réponse acceptée indique la méthode correcte pour définir l'état mais ne conduit pas à une zone de sélection qui fonctionne correctement.

import React, { useState } from "react"; 
import ReactDOM from "react-dom";

const initialValue = { id: 0,value: " --- Select a State ---" };

const options = [
    { id: 1, value: "Alabama" },
    { id: 2, value: "Georgia" },
    { id: 3, value: "Tennessee" }
];

const StateSelector = () => {   
   const [ selected, setSelected ] = useState(initialValue);  

     return (
       <div>
          <label>Select a State:</label>
          <select value={selected}>
            {selected === initialValue && 
                <option disabled value={initialValue}>{initialValue.value}</option>}
            {options.map((localState, index) => (
               <option key={localState.id} value={localState}>
                   {localState.value}
               </option>
             ))}
          </select>
        </div>
      ); 
};

const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);
0
Avin Kavish