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?
8 Réponses :
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);
... 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?
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> ); }
cela fonctionnera avec onClick, mais le setState (oldState => [... oldState, pushsomething]) est la façon dont vous devez le faire
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
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.
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.
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/...
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é.
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
// 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
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", ],
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; }); };