Si vous avez écrit beaucoup de code React, il y a de fortes chances que vous ayez utilisé l’état de manière incorrecte. Une erreur commune à de nombreux développeurs React est de stocker les états globalement dans l’application, au lieu de les stocker dans les composants où ils sont utilisés.
Découvrez comment vous pouvez refactoriser votre code pour utiliser l’état local et pourquoi c’est toujours une bonne idée.
Exemple de base de l’état dans React
Voici une application de compteur très simple qui illustre comment l’état est typiquement géré dans React :
import {useState} from 'react'
import {Counter} from 'counter'
function App(){
const [count, setCount] = useState(0)
return <Counter count={count} setCount={setCount} />
}
export default App
Aux lignes 1 et 2, vous importez la classe useState() pour créer l’état, et le hook Compteur composant. Vous définissez le composant comptage état et setCount pour mettre à jour l’état. Ensuite, vous passez les deux à la méthode Compteur composant.
Le Comptoir rend ensuite le composant compte et appelle setCount pour incrémenter et décrémenter le compte.
function Counter({count, setCount}) {
return (
<div>
<button onClick={() => setCount(prev => prev - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(prev => prev + 1)}>+</button>
</div>
)
}
Vous n’avez pas défini la fonction compte variable et setCount localement à l’intérieur de la fonction Compteur . Vous l’avez plutôt transmis à partir du composant parent (App). En d’autres termes, vous utilisez un état global.
Le problème des états globaux
Le problème avec l’utilisation d’un état global est que vous stockez l’état dans un composant parent (ou parent d’un parent) et que vous le transmettez ensuite sous forme d’accessoires au composant qui a réellement besoin de cet état.
Parfois, c’est une bonne chose quand vous avez un état qui est partagé par de nombreux composants. Mais dans ce cas, aucun autre composant ne se préoccupe de l’état compte état à l’exception de l’état Compteur . Il est donc préférable de déplacer l’état vers le composant Compteur où il est réellement utilisé.
Déplacer l’état vers le composant enfant
Lorsque vous déplacez l’état vers le composant Compteur cela ressemblerait à ceci :
import {useState} from 'react'
function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<button onClick={() => setCount(prev => prev - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(prev => prev + 1)}>+</button>
</div>
)
}
Ensuite, à l’intérieur de votre App , vous n’avez pas besoin de transmettre quoi que ce soit au composant Compteur composant :
// imports
function App(){
return <Counter />
}
Le compteur fonctionnera exactement de la même manière qu’auparavant, mais la grande différence est que tous vos états sont localement à l’intérieur du composant Compteur . Ainsi, si vous avez besoin d’un autre compteur sur la page d’accueil, vous aurez deux compteurs indépendants. Chaque compteur est autonome et gère son propre état.
Gestion de l’état dans des applications plus complexes
Une autre situation où l’on peut utiliser un état global est celle des formulaires. Les formulaires App ci-dessous transmet les données du formulaire (email et mot de passe) et la méthode setter au composant LoginForm composant.
import { useState } from "react";
import { LoginForm } from "./LoginForm";
function App() {
const [formData, setFormData] = useState({
email: "",
password: "",
});
function updateFormData(newData) {
setFormData((prev) => {
return { ...prev, ...newData };
});
}
function onSubmit() {
console.log(formData);
}
return (
<LoginForm
data={formData}
updateData={updateFormData}
onSubmit={onSubmit}
/>
);
}
Le Formulaire de connexion prend en compte les informations de connexion et les restitue. Lorsque vous soumettez le formulaire, il appelle le composant updateData qui est également transmise par le composant parent.
function LoginForm({ onSubmit, data, updateData }) {
function handleSubmit(e) {
e.preventDefault();
onSubmit();
}
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
value={data.email}
onChange={(e) => updateData({ email: e.target.value })}
/>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
value={data.password}
onChange={(e) => updateData({ password: e.target.value })}
/>
<button type="submit">Submit</button>
</form>
);
}
Plutôt que de gérer l’état sur le composant parent, il est préférable de déplacer l’état dans la fonction LoginForm.jsqui est l’endroit où vous utiliserez le code. Ce faisant, chaque composant est autonome et ne dépend pas d’un autre composant (c’est-à-dire le parent) pour les données. Voici la version modifiée du code Formulaire de connexion:
import { useRef } from "react";
function LoginForm({ onSubmit }) {
const emailRef = useRef();
const passwordRef = useRef();
function handleSubmit(e) {
e.preventDefault();
onSubmit({
email: emailRef.current.value,
password: passwordRef.current.value,
});
}
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email</label>
<input type="email" id="email" ref={emailRef} />
<label htmlFor="password">Password</label>
<input type="password" id="password" ref={passwordRef} />
<button type="submit">Submit</button>
</form>
);
}
Ici, vous liez l’entrée à une variable en utilisant ref et les attributs de la useRef React, plutôt que de transmettre directement les méthodes de mise à jour. Cela vous permet de supprimer le code verbeux et d’optimiser les performances du formulaire à l’aide du crochet useRef.
Dans le composant parent (App.js), vous pouvez supprimer à la fois l’état global et l’état de l’application. updateFormData() car vous n’en avez plus besoin. La seule fonction restante est onSubmit()que vous invoquez à l’intérieur de l’élément Formulaire de connexion pour enregistrer les détails de la connexion sur la console.
function App() {
function onSubmit(formData) {
console.log(formData);
}
return (
<LoginForm
data={formData}
updateData={updateFormData}
onSubmit={onSubmit}
/>
);
}
Non seulement vous avez rendu votre état aussi local que possible, mais vous avez en fait supprimé le besoin d’un état (et utilisé refs à la place). Ainsi, votre App a été considérablement simplifié (il n’a plus qu’une seule fonction).
Votre Formulaire de connexion Le composant a également été simplifié car il n’est plus nécessaire de se préoccuper de la mise à jour de l’état. Au lieu de cela, il suffit de garder la trace de deux refset c’est tout.
Gestion de l’état partagé
Il y a un problème avec l’approche qui consiste à rendre l’état aussi local que possible. Vous rencontrerez souvent des scénarios où le composant parent n’utilise pas l’état, mais le transmet à plusieurs composants.
Un exemple est d’avoir un composant TodoContainer Composant parent avec deux composants enfants : Liste des tâches et TodoCount.
function TodoContainer() {
const [todos, setTodos] = useState([])
return (
<>
<TodoList todos={todos}>
<TodoCount todos={todos}>
</>
)
}
Ces deux composantes enfantines nécessitent l’utilisation du todos état, donc TodoContainer le transmet à chacun d’entre eux. Dans de tels scénarios, vous devez rendre l’état aussi local que possible. Dans l’exemple ci-dessus, le placer à l’intérieur de l’élément TodosContainer est aussi local que possible.
Si vous deviez mettre cet État dans votre App Le composant de l’application n’est pas aussi local que possible parce qu’il n’est pas le parent le plus proche des deux composants qui ont besoin des données.
Pour les applications de grande taille, la gestion de l’état uniquement avec le composant useState() peut s’avérer difficile. Dans de tels cas, vous devrez peut-être opter pour l’API React Context ou React Redux pour gérer efficacement l’état.
En savoir plus sur les hooks React
Les hooks constituent la base de React. En utilisant les hooks dans React, vous pouvez éviter d’écrire du code long qui utiliserait autrement des classes. Le hook useState() est sans conteste le hook React le plus utilisé, mais il en existe beaucoup d’autres comme useEffect(), useRef(), et useContext().
Si vous cherchez à devenir compétent dans le développement d’applications avec React, alors vous devez savoir comment utiliser ces hooks dans votre application.