React Hooks: Comment démarrer et créer le vôtre

Les Hooks ont pris d'assaut le monde de React. Dans ce didacticiel, nous allons examiner ce que sont les hooks et comment vous les utilisez. Je vais vous présenter quelques crochets courants fournis avec React et vous montrer comment écrire le vôtre. Lorsque vous aurez terminé, vous pourrez utiliser des hooks dans vos propres projets React.
Que sont les hooks React?
Les hooks React sont des fonctions spéciales qui vous permettent de «vous connecter» aux fonctionnalités React de function Composants. Par exemple, le crochet useState
vous permet d'ajouter un état, tandis que useEffect
vous permet d'effectuer des effets secondaires. Auparavant, les effets secondaires étaient mis en œuvre à l'aide de méthodes de cycle de vie. Avec Hooks, ce n'est plus nécessaire.
Cela signifie que vous n'avez plus besoin de définir une classe lors de la construction d'un composant React. Il s'avère que l'architecture de classe utilisée dans React est la cause de nombreux défis auxquels les développeurs React sont confrontés chaque jour. Nous nous retrouvons souvent à écrire des composants volumineux et complexes difficiles à décomposer. Le code associé est réparti sur plusieurs méthodes de cycle de vie, ce qui devient difficile à lire, à maintenir et à tester. De plus, nous devons traiter le mot-clé this
lors de l'accès à état
accessoires
et méthodes. Nous devons également lier des méthodes à ce
pour nous assurer qu’elles sont accessibles dans le composant. Ensuite, nous avons le problème de forage excessif des hélices – également connu sous le nom de l'enfer des enveloppeurs – lorsqu'il s'agit de composants d'ordre supérieur. en isolement et réutilisation dans vos projets. Cela ne vous prendra qu'une heure pour vous familiariser avec eux, mais cela vous fera penser différemment à la façon dont vous écrivez le code React.
Les Hooks React ont été annoncés pour la première fois lors d'une conférence React qui s'est tenue en octobre 2018, et ils ont été officiellement mis à disposition dans React 16.8. La fonctionnalité est toujours en cours de développement; il existe encore un certain nombre de fonctionnalités de la classe React en cours de migration vers Hooks. La bonne nouvelle est que vous pouvez commencer à les utiliser dès maintenant. Vous pouvez toujours utiliser les composants de la classe React si vous le souhaitez, mais je doute que vous le souhaitiez après avoir lu ce guide d'introduction.
Si j'ai piqué votre curiosité, plongeons-nous et voyons quelques exemples pratiques.
Prérequis
Ce tutoriel est destiné aux personnes qui ont une compréhension de base de ce qu'est React et de son fonctionnement. Si vous êtes un débutant React, veuillez consulter notre tutoriel de démarrage avec React avant de continuer ici.
Si vous souhaitez suivre les exemples, vous devez avoir une application React déjà configurée. Le moyen le plus simple de le faire est d'utiliser l'outil Create React App. Pour l'utiliser, vous aurez installé Node et npm. Si ce n’est pas le cas, rendez-vous sur la page de téléchargement de Node.js et récupérez la dernière version de votre système (npm est fourni avec Node). Vous pouvez également consulter notre tutoriel sur l'installation de Node à l'aide d'un gestionnaire de version .
Une fois Node installé, vous pouvez créer une nouvelle application React comme ceci:
npx create-react-app myapp
Cela créera un dossier myapp
. Accédez à ce dossier et démarrez le serveur de développement comme suit:
cd myapp
npm début
Votre navigateur par défaut s'ouvrira et vous verrez votre nouvelle application React. Pour les besoins de ce didacticiel, vous pouvez utiliser le composant App
qui se trouve dans src / App.js
.
Vous pouvez également trouver le code pour ce tutoriel sur GitHub ainsi qu'une démo du code fini à la fin de ce tutoriel.
Le useState
Hook
Regardons maintenant du code. Le crochet useState est probablement le crochet le plus courant livré avec React. Comme son nom l'indique, il vous permet d'utiliser state
dans un composant de fonction.
Considérez le composant de classe React suivant:
import React from "react" [19659024];
export default class ClassDemo extend React . Component {
constructor ( accessoires ) {
super ( accessoires ) ;
this . état = {
name : "Agata"
} ;
this . handleNameChange = this . handleNameChange . bind ( this ) ;
}
handleNameChange ( e ) {
this [19659024]. setState ( {
name : e . target . value
} ) ;
}
render ([19659024]) {
return (
< section >
< form autoComplete = "off" >
< section >
< label htmlFor = "name" > Name < / étiquette >
< entrée
type = "texte"
nom = "nom"
id = "nom"
value = { this . state . name }
onChange = { this . handleNameChange }
/ >
< / section > [19659086] < / formulaire >
< p > Bonjour { this . state . nom } < / p >
< / section >
) ; [19659061]}
}
Si vous suivez avec Create React App, remplacez simplement le contenu de App.js
par ce qui précède.
Voici à quoi ça ressemble:
Donnez-vous une minute pour comprendre le code. Dans le constructeur, nous déclarons une propriété name
sur notre objet state
ainsi que la liaison d'une fonction handleNameChange
à l'instance du composant. Nous avons alors un formulaire avec une entrée, dont la valeur est fixée à this.state.name
. La valeur contenue dans this.state.name
est également sortie sur la page sous la forme d'un message d'accueil.
Lorsqu'un utilisateur tape quelque chose dans le champ d'entrée, la fonction handleNameChange
est appelée, qui met à jour l'état
et par conséquent le message d'accueil.
Maintenant, nous allons écrire une nouvelle version de ce code en utilisant le useState
Hook. Sa syntaxe ressemble à ceci:
const [ state setState ] = useState ( initialState ) ;
Lorsque vous appelez la fonction useState
elle renvoie deux éléments:
- state : le nom de votre état – tel que
this.state.name
outhis.state.location
. - setState : une fonction pour définir une nouvelle valeur pour votre état. Similaire à
this.setState ({name: newValue})
.
Le initialState
est la valeur par défaut que vous donnez à votre nouvel état déclaré lors de la phase de déclaration d'état. Maintenant que vous avez une idée de ce qu'est useState
mettons-le en action:
import React { useState } from "react" ;
export default function HookDemo ( props ) {[19659166] const [ name setName ] = useState ( "Agata" ) ; [19659174] function handleNameChange ( e ) {
setName ( e . target . value ) ;
}
return (
< section >
< form autoComplete = " off ">
< section >
< label htmlFor = " name "> Name [196590] 88] < / étiquette >
< entrée
type = "texte"
nom = "nom"
id = "nom"
valeur = { nom }
onChange = { handleNameChange }
/ >
< / section >
< / formulaire >
< p > Bonjour { nom } < / p >
< / section >
) ;
}
Prenez note des différences entre cette version de fonction et la version de classe. C'est déjà beaucoup plus compact et plus facile à comprendre que la version de classe, mais ils font tous les deux exactement la même chose. Passons en revue les différences:
- Le constructeur de classe entier a été remplacé par le
useState
Hook, qui ne se compose que d'une seule ligne. - Parce que le
useState
Hook renvoie local variables, vous n'avez plus besoin d'utiliser le mot-cléthis
pour référencer votre fonction ou vos variables d'état. Honnêtement, c'est un problème majeur pour la plupart des développeurs JavaScript, car on ne sait pas toujours quand utiliserce
. - Le code JSX est maintenant plus propre car vous pouvez référencer les valeurs d'état local sans utiliser
this.state
.
J'espère que vous êtes impressionné maintenant! Vous vous demandez peut-être quoi faire lorsque vous devez déclarer plusieurs valeurs d'état. La réponse est assez simple: il suffit d'appeler un autre useState
Hook. Vous pouvez déclarer autant de fois que vous le souhaitez, à condition de ne pas trop compliquer votre composant.
Remarque: lorsque vous utilisez React Hooks, assurez-vous de les déclarer en haut de votre composant et jamais dans un conditionnel. [19659229] Multiple Mais que se passe-t-il si nous voulons déclarer plus d'une propriété dans l'état? Aucun problème. Utilisez simplement plusieurs appels à Voici un exemple de composant avec plusieurs C'est assez simple, n'est-ce pas? Faire la même chose dans la version de classe vous obligerait à utiliser encore plus le mot-clé Maintenant, passons au prochain React Hook de base. ] La plupart des composants React sont nécessaires pour effectuer une opération spécifique telle que la récupération de données, l'abonnement à un flux de données ou la modification manuelle du DOM. Ces types d'opérations sont connus comme effets secondaires . Dans les composants basés sur les classes, nous placerions normalement notre code d'effets secondaires dans Voici un exemple simple: Ce morceau de code définira le titre du document, en fonction de ce qui est conservé dans l'état. Cependant, lorsque vous essayez d'apporter des modifications aux valeurs d'état via le formulaire, rien ne se passe. Pour résoudre ce problème, vous devez ajouter une autre méthode de cycle de vie: La mise à jour du formulaire devrait également mettre à jour le titre du document. Voyons comment nous pouvons implémenter la même logique en utilisant le crochet Avec juste ces quelques lignes de code, nous avons implémenté le travail de deux méthodes de cycle de vie dans une fonction simple. C'était un exemple simple. Cependant, dans certains cas, vous devez écrire du code de nettoyage, comme la désinscription d'un flux de données ou la désinscription d'un écouteur d'événements. Voyons un exemple de la façon dont cela est normalement implémenté dans un composant de classe React: Le code ci-dessus affichera la résolution actuelle de la fenêtre de votre navigateur. Redimensionnez la fenêtre et vous devriez voir les numéros se mettre à jour automatiquement. Si vous appuyez sur F11 dans Chrome, il devrait afficher la pleine résolution de votre moniteur. Nous avons également utilisé la méthode du cycle de vie Répliquons le code de classe ci-dessus dans notre version Hook. Nous devrons définir un troisième Étonnamment, cette version Hook du code fait exactement la même chose. Il est plus propre et plus compact. L'avantage de mettre du code dans sa propre déclaration Avez-vous remarqué que nous retournons une fonction dans ce Maintenant que vous avez appris sur les crochets Nous le ferons en extrayant la fonctionnalité ] Créez une nouvelle fonction comme suit: Ensuite, dans le composant, vous devrez remplacer ce code: … avec ceci: Supprimer le deuxième code Maintenant que nous avons créé notre premier Hook personnalisé, faisons de même pour le titre du document. Tout d'abord, supprimez l'appel restant à Enfin, appelez-le depuis le composant: Revenez à votre navigateur et entrez quelque chose dans les champs de saisie. Le titre du document devrait changer comme avant. Enfin, refactorisons les champs du formulaire. Nous voulons créer un Hook pour garder sa valeur synchronisée avec une valeur correspondante dans state. Commençons par le Hook personnalisé. Ajoutez ce qui suit en dehors du composant: Mettez ensuite à jour le composant pour l'utiliser: Parcourez le code lentement et identifiez toutes les modifications que nous avons apportées. Assez bien, non? Notre composant est beaucoup plus compact. Pour les besoins de ce tutoriel, nous avons déclaré nos Hooks comme des fonctions dans le même fichier que le composant qui les utilise. Cependant, dans un projet React normal, vous auriez un dossier Nous pourrions même aller aussi loin. quant à l'empaquetage de Pour référence, voici la version complète du composant Hooks: The Hook’s component should render and behave exactly like the class component version: If you compare the Hook version with the class component version, you’ll realize that the Hook feature reduces your component code by at least 30%. You can even reduce your code further by exporting the reusable functions to an npm library. Next let’s look at how we can use other people’s Hooks in our code. Let’s look at an example of how you can fetch data from a REST JSON API using Axios and React Hooks. If you’re following along at home, you’ll need to install the Axios library: Change your component to look like this: We should expect the following output: It’s possible to refactor the above code by building your own custom Hook in such as way that we no longer need to use You can install the package using the command: Below, I’ve refactored the above code using Not only have we gotten rid of the The lesson here is to avoid reinventing the wheel. Google is your friend. In the JavaScript world, there’s a high chance that someone has already solved the problem you’re trying to tackle. Below is a live demo of what we’ve accomplished so far: These are the basic React Hooks that you’ll come across in your day-to-day React projects: We also have additional official React Hooks that you may need to use, depending on your project requirements: You can read all about these Hooks in the official React documentation. The React community has responded positively to the new React Hooks feature. There’s already an open-source repository called awesome-react-hooksand hundreds of custom React Hooks have been submitted to this repository. Here’s a quick example of one of those Hooks for storing values in local storage: You’ll need to install the Pretty neat, right? The introduction of React Hooks has made a big splash. Its waves have moved beyond the React community into the JavaScript world. This is because Hooks are a new concept that can benefit the entire JavaScript ecosystem. In fact, the Vue.js team has recently released something similar called the Composition API. There’s also talk of React Hooks and the Context API overthrowing Redux from its state management throne. Clearly, Hooks have made coding much simpler and have changed the way we’ll write new code. If you’re like me, you probably have a strong urge to rewrite all your React component classes and replace them with functional component Hooks. Do note that this isn’t really necessary: the React team doesn’t plan to deprecate React class components. You should also be aware that not all React class lifecycle methods are possible with Hooks yet. You may have to stick with React component classes a bit longer. If you feel confident enough with your new knowledge of basic React Hooks, I’d like to leave you with a challenge. Refactor this Countdown timer class using React Hooks to make it as clean and compact as possible. Happy coding, and let me know how you get on! useState
Hooks useState
. useState
Hooks: import React { useState } from "react" ;
export default function HookDemo ( props ) {
const [ name setName ] = useState ( "Agata ") ;
const [ location setLocation ] = useState (" Nairobi ") ;
function handleNameChange ( e ) {
setName ( e . [19659042] target . value ) ;
}
function handleLocationChange ( e ) {
setLocation ( e . target . value ) [19659024];
}
return (
< section >
< form autoComplete = "off" > [19659086] < section >
< label htmlFor = "name" > Name < / label >
< entrée
type = "texte"
nom = "nom"
id = "nom"
valeur = { nom }
onChange = { handleNameChange }
/ >
< / section >
< section >
< label htmlFor = "location" > Location < / label >
< entrée
type = "texte"
name = "emplacement"
id = "emplacement"
valeur = { emplacement }
onChange = { handleLocationChange }
/ >
< / section >
< / formulaire >
< p >
Bonjour { name } from { location }
< / p >
< / section >
) ;
}
this
. useEffect
Hook componentDidMount
et componentDidUpdate
. Ce sont des méthodes de cycle de vie qui nous permettent de déclencher la méthode de rendu au bon moment. componentDidMount () {
document . title = this . state . name + "from" + this . état . location ;
}
componentDidUpdate () {
document . title = this ]. état . nom + "from" + this . state . location ];
}
useEffect
. Mettez à jour le composant de fonction ci-dessus comme suit: import React { useState useEffect } from "react" ;
useEffect ( () => {
document . title = name + "de" + lieu ;
} ) ;
Ajout du code de nettoyage
import React from "react" ;
export default class ClassDemo extend React . Component {
constructor ( props ) {
super ] ( accessoires ) ;
ceci . état = {
résolution : {
width : window . innerWidth
height : window . innerHeight
}
} ;
this . handleResize = this [19659024]. handleResize . bind ( this ) ;
}
componentDidMount () {
window . addEventListener ( "resize" this . handleResize ) ;
}
componentDidUpdate () {
window . addEventListener ( "resize" this . handleResize ) ;
}
componentWillUnmount () {
window . removeEventListener ([19659087] 'redimensionner' this . handleResize ) ;
} [19659062] handleResize () {
this . setState ( {
résolution : {
width : window . innerWidth
height : window . innerHeight
}
} ) ;
}
render () [19659031] {
renvoie (
< section >
< h3 >
{ this . état . résolution . largeur } x { ceci . état . résolution [19659024]. hauteur }
< / h3 >
< / section >
)
}
}
componentWillUnmount
pour annuler l’enregistrement de l’événement resize
. hook useState
et un second useEffect
Hook pour gérer cette nouvelle fonctionnalité: import React { useState useEffect } from "react" ;
export default function HookDemo ( props ) {
...
const [ resolution setResolution ] = useState ( {
width : window . innerWidth
height : window . innerHeight
} ) ;
useEffect ( () => {
const handleResize = () => {
setResolution ( {)
width : window . innerWidth
height : window . innerHeight
} ) ;
} ;
window . addEventListener [19659024] ( "resize" handleResize ) ;
return () => {
document . title = 'React Hooks Demo' ;
window . removeEventListener ( "resize" handleResize ) ;
} ;
} ) ;
...
return (
< section >
...
< h3 >
{ resolution . width } x { resolution . hauteur }
</ h3 >
</ section >
) ;
}
useEffect
est que nous pouvons facilement le tester puisque le code est isolé. useEffect
Hook? C'est parce que toute fonction que vous retournez dans une fonction useEffect
sera considérée comme le code de nettoyage. Si vous ne renvoyez pas une fonction, aucun nettoyage ne sera effectué. Dans ce cas, un nettoyage est nécessaire, car vous rencontrerez autrement un message d'erreur consigné dans la console de votre navigateur indiquant «impossible d'effectuer une mise à jour de l'état React sur un composant non monté». Hooks React personnalisés
useState
et useEffect
laissez-moi vous montrer une façon vraiment cool de rendre votre code encore plus compact, plus propre et réutilisable que ce que nous avons réalisé jusqu'à présent . Nous allons créer un Hook personnalisé pour simplifier encore plus notre code. resize
et en la plaçant en dehors de notre composant. function useWindowResolution () {
const [ width setWidth ]] = useState ( window . innerWidth ) ;
const [ height setHeight ] = useState ( window . innerHeight ) ;
useEffect ( ] () => {
const handleResize = () => {
setWidth [19659024] ( window . innerWidth ) ;
setHei ght ( window . innerHeight ) ;
} ;
window . addEventListener ([19659087] "resize" handleResize ) ;
return () => {
window . removeEventListener ( "resize" handleResize ) ;
} ;
} largeur hauteur ] ) ;
retour {
largeur
la taille
} ;
}
const [ resolution setResolution ] = useState ( {
width : window . innerWidth
height : window . innerHeight
} ) ;
const resolution = useWindowResolution () ;
useEffect
. Enregistrez votre fichier et testez-le. Tout devrait fonctionner comme avant. useEffect
à l'intérieur du composant. Ensuite, en dehors du composant, ajoutez le code suivant: function useDocumentTitle ( title ) {
useEffect ( () ) => {
document . title = title ;
} ) ;
}
useDocumentTitle ( name + "from" + location ) ;
function useFormInput ( initialValue ) {
const [ value ] setValue ] = useState ( initialValue ) ;
function handleChange ( e ) {
setValue ( e . target . value ) ;
}
return [19659031] {
valeur
onChange : handleChange
} ;
}
export default function HookDemo ( props ) {[19659166] const nom = useFormInput ( "Agata" ) ;
const location = useFormInput [19659024] ( "Nairobi" ) ;
const resolution = useWindowResolution () ;
useDocumentTitle [19659024] ( nom . valeur + "from" + location . valeur ) ; [19659174] return (
< section >
< form autoComplete = "off" >
< section >
< label htmlFor = "name" > Name < / étiquette >
< entrée { ... nom } / >
< / section >
< section >
< label htmlFor = "location" > Location < / label >
< input { ... location } / >
< / section >
< / form >
< p >
Bonjour { name . value } from { location . value }
< / p >
< h3 >
{ resolution . width } x { resolution ]. hauteur }
< / h3 >
< / section >
) ;
}
hooks
avec chacun de ces Hooks dans un fichier séparé, qui pourrait ensuite être importé partout où il était nécessaire. useFormInput
useDocumentTitle
et useWindowResolution
Se connecte à un module externe npm, car ils sont complètement indépendants de la logique principale de notre code. Nous pouvons facilement réutiliser ces Hooks personnalisés dans d'autres parties du projet, ou même dans d'autres projets à l'avenir. import React { useState useEffect } from "react" ;
function useWindowResolution () {
const [ width setWidth ] = useState ( window . innerWidth [19659024]) ;
const [ height setHeight ] = useState ( window . innerHeight ) ;
useEffect ( () => {
const handleResize = () => {
setWidth ([19659257] window . innerWidth ) ;
setHeight ( window . innerHeight ) ;
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize ", handleResize)[19659024];
};
}, [width, height]);
return {
width,
la taille
};
}
function useDocumentTitle(title){
useEffect(() => {
document.title = title;
});
}
function useFormInput(initialValue) {
const [value, setValue] = useState(initialValue);
function handleChange(e) {
setValue(e.target.value);
}
return {
value,
onChange: handleChange
};
}
export default function HookDemo(props) {
const name = useFormInput("Agata");
const location = useFormInput("Nairobi");
const resolution = useWindowResolution();
useDocumentTitle(name.value + " from " + location.value);
return (
<section>
<form autoComplete="off">
<section>
<label htmlFor="name">Name</label>
<input {...name} />
</section>
<section>
<label htmlFor="location">Location</label>
<input {...location} />
</section>
</form>
<p>
Hello {name.value} from {location.value}
</p>
<h3>
{resolution.width} x {resolution.height}
</h3>
</section>
);
}
Fetching Data Using Third-party Hooks
npm i axios
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export default function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
const fetchData = async () => {
const result = await axios('https://jsonplaceholder.typicode.com/users');
setUsers(result.data);
};
fetchData();
}, []);
const userRows = users.map((user, index) => <li key={index}>{user.name}</li>);
return (
<div className="component">
<h1>List of Users</h1>
<ul>{userRows}</ul>
</div>
);
}
useState
and useEffect
Hooks. Luckily for us, many developers have already fulfilled this quest and published their work as a package we can install in our project. We’ll use axios-hooks by Simone Busoliwhich happens to be the most popular one.npm i axios-hooks
axios-hooks
:import React from 'react';
import useAxios from 'axios-hooks';
export default function UserListAxiosHooks() {
const [{ data, loading, error }, refetch] = useAxios(
'https://jsonplaceholder.typicode.com/users'
);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
const userRows = data.map((user, index) => <li key={index}>{user.name}</li>);
return (
<div className="component">
<h1>List of Users</h1>
<ul>{userRows}</ul>
<button onClick={refetch}>Reload</button>
</div>
);
}
useState
and useEffect
Hooks from our code, but we’ve also gained three new abilities with no extra brain-power on our part:Demo
Official React Hooks
useState
: for managing local stateuseEffect
: replaces lifecycle functionsuseContext
: allows you to easily work with the React Context API (solving the prop drilling issue)useReducer
: an advanced version of useState
for managing complex state logic. It’s quite similar to Redux.useCallback
: returns a function that returns a cacheable value. Useful for performance optimization if you want to prevent unnecessary re-renders when the input hasn’t changed.useMemo
: returns a value from a memoized function. Similar to computed
if you’re familiar with Vue.useRef
: returns a mutable ref object that persists for the lifetime of the component.useImperativeHandle
: customizes the instance value that’s exposed to parent components when using ref
.useLayoutEffect
: similar to useEffect
but fires synchronously after all DOM mutations.useDebugValue
: displays a label for custom Hooks in React Developer Tools.Summary
import useLocalStorage from "@rehooks/local-storage";
function MyComponent() {
let name = useLocalStorage("name");
return (
<div>
<h1>{name}</h1>
</div>
);
}
local-storage
Hook with npm or yarn like this to use it:npm i @rehooks/local-storage
Source link