118
votes

Méthode Push dans React Hooks (useState)?

Comment pousser l'élément à l'intérieur du hook useState du tableau React? Est-ce une ancienne méthode en état de réaction? Ou quelque chose de nouveau?

Par exemple, un exemple de push setState ?


0 commentaires

8 Réponses :


290
votes

Lorsque vous utilisez useState , vous pouvez obtenir une méthode de mise à jour pour l'élément d'état:

<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>

puis, lorsque vous souhaitez ajouter un nouvel élément, vous utilisez cette fonction et passez le nouveau tableau ou une fonction qui créera le nouveau tableau. Normalement ce dernier, puisque les mises à jour d'état sont asynchrones et parfois groupées:

const {useState, useCallback} = React;
function Example() {
    const [theArray, setTheArray] = useState([]);
    const addEntryClick = () => {
        setTheArray([...theArray, `Entry ${theArray.length}`]);
    };
    return [
        <input type="button" onClick={addEntryClick} value="Add" />,
        <div>{theArray.map(entry =>
          <div>{entry}</div>
        )}
        </div>
    ];
}

ReactDOM.render(
    <Example />,
    document.getElementById("root")
);

Parfois, vous pouvez vous en sortir sans utiliser ce formulaire de rappel, si vous ne mettez à jour le tableau dans les gestionnaires que pour certains événements utilisateur spécifiques tels que click (mais pas comme mousemove ):

<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>

Les événements pour lesquels React garantit que le rendu est vidé sont les "événements discrets" répertoriés ici .

Exemple en direct (en passant un rappel dans setTheArray ):

const {useState, useCallback} = React;
function Example() {
    const [theArray, setTheArray] = useState([]);
    const addEntryClick = () => {
        setTheArray(oldArray => [...oldArray, `Entry ${oldArray.length}`]);
    };
    return [
        <input type="button" onClick={addEntryClick} value="Add" />,
        <div>{theArray.map(entry =>
          <div>{entry}</div>
        )}
        </div>
    ];
}

ReactDOM.render(
    <Example />,
    document.getElementById("root")
);
setTheArray([...theArray, newElement]);

Parce que la seule mise à jour de theArray là-dedans est celle d'un événement de click (l'un des événements "discrets"), je pourrais m'en tirer avec une mise à jour directe dans addEntry :

setTheArray(oldArray => [...oldArray, newElement]);
const [theArray, setTheArray] = useState(initialArray);


5 commentaires

... et essayez setTheArray(currentArray => [...currentArray, newElement]) si ce qui précède ne fonctionne pas. Très probablement dans useEffect(...theArray..., []) , il est important de réaliser que theArray est une constante, donc des mises à jour fonctionnelles sont nécessaires pour les valeurs des futurs rendus


@Aprillion - Vous n'êtes pas sûr de ce que vous dites avec cet exemple useEffect ...?


Si useEffect a une liste de dépendances vide [] , il ne sera exécuté que lors du premier rendu. Ainsi, la valeur de theArray dans l'effet sera toujours initialArray . Dans les situations où setTheArray([...initialArray, newElement]) n'aurait pas de sens, et lorsque la constante theArray sera toujours égale à initialValue , des mises à jour fonctionnelles sont nécessaires.


@Aprillion - J'ai bien peur de ne toujours pas comprendre, peut-être un peu dense. :-) Pourquoi auriez-vous besoin d'un effet avec juste la valeur initiale du tableau? (Je veux dire, il peut y avoir un cas d'utilisation peu fréquent, mais ...) Et même si vous le faites, qu'est-ce que cela a à voir avec la question?


Hey @TJCrowder, j'utilise la méthode de rappel pour fusionner les anciennes données avec les nouvelles lors de la récupération des données, mais pour une raison quelconque, cela ne fonctionne pas correctement, pouvez-vous vérifier ceci pour comprendre mon problème?



5
votes

De la même manière que vous le faites avec l'état "normal" dans les composants de la classe React.

exemple:

function App() {
  const [state, setState] = useState([]);

  return (
    <div>
      <p>You clicked {state.join(" and ")}</p>
      //destructuring
      <button onClick={() => setState([...state, "again"])}>Click me</button>
      //old way
      <button onClick={() => setState(state.concat("again"))}>Click me</button>
    </div>
  );
}


1 commentaires

cela fonctionnera avec onClick, mais le setState (oldState => [... oldState, pushsomething]) est la façon dont vous devez le faire



48
votes

Pour développer un peu plus, voici quelques exemples courants. Commençant par:

let specificArrayInObject = theObject.array.slice();
specificArrayInObject.push(newValue);
const newObj = { ...theObject, [event.target.name]: specificArrayInObject };
theObject(newObj);

Élément de poussée à la fin du tableau

setTheArray(prevState => [...prevState, {currentOrNewKey: newValue}]);

Élément Push / update à la fin de l'objet

setTheObject(prevState => ({ ...prevState, currentOrNewKey: newValue}));

Élément Push / update à la fin du tableau d'objets

setTheArray(prevArray => [...prevArray, newValue])

Élément de poussée à la fin de l'objet des tableaux

const [theArray, setTheArray] = useState(initialArray);
const [theObject, setTheObject] = useState(initialObject);

Voici également quelques exemples de travail. https://codesandbox.io/s/reacthooks-push-r991u


1 commentaires

Merci pour tous les exemples. La chose exacte avec laquelle j'avais un problème était votre élément Push à la fin de l'objet des tableaux . J'ai essayé tellement de choses différentes, mais je ne pouvais tout simplement pas les bricoler.



2
votes

setTheArray([...theArray, newElement]); est la réponse la plus simple mais attention à la mutation des éléments dans theArray . Utilisez le clonage en profondeur des éléments du tableau.


1 commentaires

Le clonage profond que vous mentionnez, cela signifie-t-il recevoir comme objA. UseState et concatre l'objA avec objB? Identique à ce lien? gist.githubusercontent.com/kahsing/...



1
votes

La méthode la plus recommandée consiste à utiliser ensemble la fonction wrapper et l'opérateur spread. Par exemple, si vous avez initialisé un état appelé name comme celui-ci,

const [names, setNames] = useState([])

Vous pouvez pousser vers ce tableau comme ceci,

setNames(names => [...names, newName])

J'espère que ça t'as aidé.


2 commentaires

Veuillez ne pas publier de réponses par lien uniquement. Le lien pourrait être rompu à l'avenir. Au lieu de cela, créez une rédaction de cet article et assurez-vous de répondre réellement à la question.


Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien pour référence. Les réponses aux liens uniquement peuvent devenir invalides si la page liée change. - De l'avis



3
votes
// Save search term state to React Hooks with spread operator and wrapper function

// Using .concat(), no wrapper function (not recommended)
setSearches(searches.concat(query))

// Using .concat(), wrapper function (recommended)
setSearches(searches => searches.concat(query))

// Spread operator, no wrapper function (not recommended)
setSearches([...searches, query])

// Spread operator, wrapper function (recommended)
setSearches(searches => [...searches, query])

  https://medium.com/javascript-in-plain-english/how-to-add-to-an-array-in-react-state-3d08ddb2e1dc

0 commentaires

0
votes

J'ai essayé les méthodes ci-dessus pour pousser un objet dans un tableau d'objets dans useState mais j'ai eu l'erreur suivante lors de l'utilisation de TypeScript :

Tapez 'TxBacklog [] | undefined 'doit avoir une méthode' Symbol.iterator 'qui renvoie un iterator.ts (2488)

La configuration du tsconfig.json était apparemment correcte:

    // Define new object to be added
    const newTx = {
       txHash: '0x368eb7269eb88ba86..',
       status: 'pending'
    };
    // Push new object into array
    (txBacklog) 
       ? setTxBacklog(prevState => [ ...prevState!, newTx ])
       : setTxBacklog([newTx]);

Cette solution de contournement a résolu le problème (mon exemple de code):

Interface:

    const [txBacklog, setTxBacklog] = React.useState<TxBacklog[]>();

État variable:

   interface TxBacklog {
      status: string,
      txHash: string,
   }

Poussez le nouvel objet dans le tableau:

{
   "compilerOptions": {
   "target": "es6",
   "lib": [
      "dom",
      "dom.iterable",
      "esnext",
      "es6",
],


0 commentaires

0
votes

si vous voulez pousser après un index spécifique, vous pouvez faire comme ci-dessous:

   const handleAddAfterIndex = index => {
       setTheArray(oldItems => {
            const copyItems = [...oldItems];
            const finalItems = [];
            for (let i = 0; i < copyItems.length; i += 1) {
                if (i === index) {
                    finalItems.push(copyItems[i]);
                    finalItems.push(newItem);
                } else {
                    finalItems.push(copyItems[i]);
                }
            }
            return finalItems;
        });
    };


0 commentaires