Table of contents
Dans le dernier épisode de la série sur les Hooks personnalisés, nous avons implémenté le Hook useBoolean. Aujourd'hui, nous allons en créer un tout aussi simple et efficace : useCounter. Comme son nom l'indique, il va nous faciliter la manipulation de l'état d'un compteur. Vous êtes prêts ? Allons-y. 🚀
Motivation
Comme toujours, voyons d'abord pourquoi nous voudrions implémenter ce Hook. Imaginons que nous développons un site web d'e-commerce. Lorsqu'un client souhaite acheter un produit sur notre site, il doit également pouvoir sélectionner la quantité. L'interface pourrait donc ressembler à celle ci-dessous (ne faisons pas attention au style).
Et le code source du composant Cart
ressemblerait à cela :
const Cart = () => {
const [quantity, setQuantity] = useState(0);
return (
<div className="Cart">
<h1>My Cart</h1>
<Item
label="My awesome item"
quantity={quantity}
onIncrement={() => setQuantity((q) => q + 1)}
onDecrement={() => setQuantity((q) => q - 1)}
onReset={() => setQuantity(0)}
/>
</div>
);
}
Bien sûr, cet exemple est extrêmement simplifié afin de se concentrer sur ce qui nous intéresse le plus dans cet article.
Le composant ci-dessus pourrait être simplifié en se débarrassant de ces horribles fonctions fléchées. De plus, comme
nous allons très probablement réutiliser cette logique dans d'autres parties de notre application, nous devrions
l'extraire dans un Hook séparé pour éviter la duplication de code. C'est pour cela que nous allons créer le Hook
useCounter
. Passons maintenant à l'implémentation. 😎
Implémentation
Notre Hook aura donc un état pour contenir la valeur du compteur. Il disposera également de 3 méthodes pour mettre sa
valeur à jour : increment
, decrement
et reset
. Dans cette optique, nous pouvons créer notre Hook de la façon
suivante :
const useCounter = (initialValue) => {
const [value, setValue] = useState(initialValue);
const increment = () => setValue(c => c + 1);
const decrement = () => setValue(c => c - 1);
const reset = () => setValue(initialValue);
return { value, increment, decrement, reset };
};
Certains d'entre vous se demanderont peut-être pourquoi les 3 méthodes exportées ne sont pas encapsulées dans un appel
à useCallback
, qui permettrait de ne pas les récréer à chaque nouveau rendu du composant. Dans notre cas, le composant est
si simple qu'utiliser le Hook useCallback
3 fois pour améliorer les performances pourrait avoir l'effet inverse. Ce Hook devrait
plutôt être utilisé si vous savez que le Hook que vous développez sera utilisé dans des composants plus complexes et avec
de grandes quantités de données.
Pour plus d'informations, n'hésitez-pas à jeter un œil à cet article de Dmitri Pavlutin, qui explique en détail pourquoi, quand et comment utiliser le Hook
useCallback
. Cela s'applique également aux HooksuseMemo
etuseRef
.
Ceci étant dit, notre nouveau Hook personnalisé est désormais prêt à être utilisé ! 🥳
Utilisation
Revenons à notre exemple de site web d'e-commerce. Maintenant que nous avons à notre disposition un tout nouveau Hook
personnalisé, voici comment le code du composant Cart
peut être simplifié :
function Cart() {
const quantity = useCounter(0);
return (
<div className="Cart">
<h1>My Cart</h1>
<Item
label="My awesome item"
quantity={quantity.value}
onIncrement={quantity.increment}
onDecrement={quantity.decrement}
onReset={quantity.reset}
/>
</div>
);
}
Nous nous sommes débarrassés de toutes les fonctions fléchées, ce qui nous donne un code plus propre et plus facile à lire.
Idées d'Améliorations
Pour aller plus loin, voici quelques idées pour améliorer le Hook useCounter
. N'hésitez-pas à essayer d'en implémenter
une ou plusieurs afin de pratiquer de votre côté.
- Ajouter un pas d'incrémentation et de décrémentation :
counter.increment(step)
- Définir une valeur minimale et une valeur maximale :
useCounter({ min: 0, max: 10, initial: 0 })
- Définir manuellement la valeur du compteur :
counter.set(value)
Conclusion
Avec ce tout nouveau Hook, nous avons désormais une corde de plus à notre arc. Les Hooks que nous avons créés jusqu'à maintenant étaient très simples (certains les considèreront même comme superflus). Dans les prochains articles de cette série, nous commencerons à implémenter des Hooks un peu plus complexes pour réellement nous aider à simplifier nos composants et à éviter la duplication de code.
Code source disponible sur CodeSandbox