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;
});
};