
Avec la sortie du nouveau React 16.6.0, HOOKS (PROPOSAL) est apparu dans la documentation. Ils sont maintenant disponibles dans react 17.0.0-alpha et sont discutés dans le RFC ouvert : React Hooks . Voyons ce que c'est et pourquoi c'est nécessaire sous la coupe.
Oui, c'est RFC et vous pouvez influencer la mise en œuvre finale en discutant avec les créateurs de réagir pourquoi ils ont choisi telle ou telle approche.
Voyons à quoi ressemble un crochet standard:
import { useState } from 'react'; function Example() {
Essayez de penser à ce code, c'est un teaser et à la fin de l'article, vous comprendrez déjà ce que cela signifie. La première chose que vous devez savoir est que cela ne rompt pas la compatibilité descendante et peut-être qu'ils seront ajoutés en 16.7 après avoir collecté les commentaires et suggestions dans le RFC.
Comme les gars l'assurent, ce n'est pas un plan pour couper les classes d'un réactif.
De plus, les hooks ne remplacent pas les concepts actuels de la réaction, tout est à la place des accessoires / état / contexte / références. C'est juste une autre façon d'utiliser leur pouvoir.
La motivation
Les crochets résolvent à première vue les problèmes non connectés qui sont apparus avec le soutien de dizaines de milliers de composants sur 5 ans à partir de Facebook.
La chose la plus difficile est de réutiliser la logique dans les composants avec état, la réaction n'a aucun moyen d'attacher un comportement réutilisable au composant (par exemple, le connecter au référentiel). Si vous avez travaillé avec React, vous connaissez le concept de HOC (high-order-component) ou d'accessoires de rendu. Ce sont des modèles assez bons, mais parfois ils sont utilisés de manière excessive, ils nécessitent une restructuration des composants afin qu'ils puissent être utilisés, ce qui rend généralement le code plus lourd. Il vaut la peine de regarder une application React typique et il deviendra clair ce qui est en jeu.

C'est ce qu'on appelle l' enfer enveloppé - l'enfer enveloppant.
Une application de HOC seule est normale dans les réalités actuelles, ils ont connecté le composant au magasin / thème / localisation / jarret personnalisé, je pense que tout le monde le sait.
Il devient clair que la réaction a besoin d'un autre mécanisme primitif pour séparer la logique.
À l'aide de crochets, nous pouvons extraire l'état d'un composant afin qu'il puisse être testé et réutilisé. Les crochets vous permettent de réutiliser la logique d'état sans changer la hiérarchie des composants. Cela facilite l'échange de liens entre de nombreux composants ou l'ensemble du système. En outre, les composants de classe semblent assez effrayants, nous décrivons les méthodes de cycle de vie de componentDidMount
/ shouldComponentUpdate
/ componentDidUpdate
, l'état du composant, créez des méthodes pour travailler avec l'état / côté, liez des méthodes pour l'instance de composant, et ainsi de suite. En règle générale, ces composants vont au-delà de x lignes, où x est assez difficile à comprendre.
Les crochets vous permettent de faire de même en brisant la logique entre les composants en petites fonctions et en les utilisant à l'intérieur des composants.
Les cours sont difficiles pour les gens et pour les voitures
L'observation des cours Facebook est un gros obstacle lors de l'apprentissage de React. Vous devez comprendre comment this
fonctionne, et cela ne fonctionne pas comme dans d'autres langages de programmation, vous devez également vous rappeler de lier les gestionnaires d'événements. Sans phrases de syntaxe stables, le code semble très verbeux. Les gens comprennent les accessoires / modèles d'état et le flux de données dit descendant, mais les classes sont assez difficiles à comprendre.
Surtout si ce n'est pas limité aux modèles, il n'y a pas si longtemps, les gars de la réaction ont expérimenté la disposition des composants avec Prepack et ont vu des résultats prometteurs, mais néanmoins, les composants de la classe vous permettent de créer de mauvais modèles involontaires qui font disparaître ces optimisations, les classes ne migrent pas non plus très bien quand Les classes de rechargement à chaud le rendent peu fiable. Tout d'abord, les gars voulaient fournir une API qui prend en charge toutes les optimisations et fonctionne bien avec un redémarrage à chaud.
Jetez un œil aux crochets
Crochet d'état
Le code ci-dessous rend un paragraphe et un bouton, et si nous cliquons sur le bouton, la valeur du paragraphe sera incrémentée.
import { useState } from 'react'; function Example() {
De cela, nous pouvons conclure que ce crochet fonctionne de manière similaire avec un concept tel que l' state
.
Une méthode useState
un peu plus détaillée prend un argument, il s'agit de la valeur par défaut et retourne un tuple dans lequel se trouve la valeur elle-même et la méthode pour la changer, contrairement à setState, setCount ne fusionnera pas les valeurs, mais les mettra simplement à jour. Nous pouvons également utiliser plusieurs déclarations d'état, par exemple:
function ExampleWithManyStates() {
Ainsi, nous créons plusieurs états à la fois et nous n'avons pas besoin de réfléchir à la façon de les décomposer d'une manière ou d'une autre. Ainsi, on peut distinguer que les hooks sont des fonctions qui vous permettent de "vous connecter" aux puces des composants de classe, tout comme les hooks ne fonctionnent pas à l'intérieur des classes, il est important de s'en souvenir.
Crochet d'effet
Souvent dans les composants de classe, nous faisons des fonctions d'effets secondaires, par exemple, souscrivez à des événements ou faites des demandes de données, généralement pour cela, nous utilisons les méthodes componentDidMount
/ componentDidUpdate
import { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0);
Lorsque nous appelons useEffect
nous disons à la réaction de faire un «effet secondaire» après la mise à jour des modifications dans l'arborescence DOM. Les effets sont déclarés à l'intérieur du composant, ils ont donc accès aux accessoires / état. Et nous pouvons les créer exactement de la même manière que nous le souhaitons.
function FriendStatusWithCounter(props) { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); const [isOnline, setIsOnline] = useState(null); useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); function handleStatusChange(status) { setIsOnline(status.isOnline); }
Immédiatement, il convient de prêter attention au deuxième effet secondaire, nous renvoyons la fonction, nous le faisons afin d'effectuer certaines actions après que le composant a effectué le démontage, dans la nouvelle API, cela s'appelle les effets avec le nettoyage. D'autres effets peuvent renvoyer n'importe quoi.
Règles de crochet
Les crochets ne sont que des fonctions javascript, mais ils ne nécessitent que deux règles:
- Les hooks doivent être exécutés tout en haut de la hiérarchie des fonctions (cela signifie que vous ne devez pas appeler de hooks dans des conditions et des boucles, sinon la réaction ne peut pas garantir l'ordre d'exécution des hooks)
- Appeler les hooks uniquement dans les fonctions React ou les composants fonctionnels ou appeler les hooks à partir de hooks personnalisés (ci-dessous).
Pour suivre ces règles, les gars de l'équipe React ont créé un plugin linter qui générera une erreur si vous appelez des hooks dans des composants de classe ou dans des boucles et des conditions.
Crochets personnalisés
Dans le même temps, nous voulons réutiliser la logique des composants avec état, généralement des modèles HOC ou des accessoires de rendu sont utilisés pour cela, mais ils créent un volume supplémentaire de notre application.
Par exemple, nous décrivons la fonction suivante:
import { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); function handleStatusChange(status) { setIsOnline(status.isOnline); } useEffect(() => { ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange); }; }); return isOnline; }
Réalisez ce code, ce sera un hook personnalisé que nous pourrons appeler dans différents composants. Par exemple, comme ceci:
function FriendStatus(props) { const isOnline = useFriendStatus(props.friend.id); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; }
ou alors
function FriendListItem(props) { const isOnline = useFriendStatus(props.friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {props.friend.name} </li> ); }
Dans tous les cas, nous réutilisons l'état du composant, chaque appel à la fonction useFriendStatus
crée un état isolé. Il convient également de noter que le début de cette fonction commence par l' utilisation du mot, ce qui signifie qu'il s'agit d'un crochet. Nous vous recommandons de suivre ce format. Vous pouvez écrire des crochets personnalisés pour tout, des animations / abonnements / minuteurs et bien plus encore.
Il y a encore quelques crochets.
useContext
useContext
vous permet d'utiliser la valeur de retour habituelle au lieu de renderProps, le contexte que nous voulons y récupérer et il nous le rendra, afin que nous puissions nous débarrasser de tous les HOC qui ont passé le contexte aux accessoires.
function Example() { const locale = useContext(LocaleContext); const theme = useContext(ThemeContext);
Et maintenant, nous pouvons simplement utiliser l'objet contextuel dans la valeur de retour.
useCallback
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
À quelle fréquence avez-vous dû créer un composant d'une classe juste pour enregistrer une référence à une méthode? Cela n'a plus besoin d'être fait, nous pouvons utiliser useCallback et nos composants ne seront pas redessinés car un nouveau lien vers onClick est arrivé.
useMemo
Nous retournons la valeur mémorisée, la valeur mémorisée signifie qu'elle est calculée uniquement lorsque l'un des arguments a changé, la deuxième fois la même chose ne sera pas calculée.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Oui, ici, vous devez dupliquer les valeurs dans le tableau afin que le crochet comprenne qu'elles n'ont pas changé.
useRef
useRef
renvoie une valeur mutée, où le champ .current
sera initialisé avec le premier argument, l'objet existera tant que le composant existera.
L'exemple le plus courant en se concentrant sur l'entrée
function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => {
useImperativeMethods
useImperativeMethods
personnalise la valeur de l'instance transmise par le parent et utilise ref directement. Comme toujours, les liens directs doivent être évités et forwardRef
doit être utilisé
function FancyInput(props, ref) { const inputRef = useRef(); useImperativeMethods(ref, () => ({ focus: () => { inputRef.current.focus(); } })); return <input ref={inputRef} ... />; } FancyInput = forwardRef(FancyInput);
Dans cet exemple, le composant qui FancyInput
peut appeler fancyInputRef.current.focus()
.
useMutationEffect
useMutationEffect
très similaire à useEffect
sauf qu'il démarre de manière synchrone au stade où la réaction modifie les valeurs DOM avant la mise à jour des composants voisins, ce hook doit être utilisé pour effectuer des mutations DOM.
Il est préférable de préférer useEffect pour éviter le blocage des changements visuels.
useLayoutEffect
useLayoutEffect
est similaire à useEffect
sauf qu'il s'exécute de manière synchrone après toutes les mises à jour DOM et le nouveau rendu synchrone. Les mises à jour prévues dans useLayoutEffect
sont appliquées de manière synchrone avant que le navigateur puisse dessiner des éléments. Vous devez également essayer d'utiliser le useEffect
standard afin de ne pas bloquer les modifications visuelles.
useReducer
useReducer
est un crochet pour créer un réducteur qui renvoie l'état et la possibilité de distribuer les modifications:
const [state, dispatch] = useReducer(reducer, initialState);
Si vous comprenez comment fonctionne Redux, vous comprenez comment fonctionne useReducer
. Le même exemple qui était avec le compteur ci-dessus uniquement via useReducer
:
const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'reset': return initialState; case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; } } function Counter({initialCount}) { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'reset'})}> Reset </button> <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ); }
UseReducer prend également 3 arguments, c'est l' action
qui doit être exécutée lors de l'initialisation du réducteur:
const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'reset': return {count: action.payload}; case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; } } function Counter({initialCount}) { const [state, dispatch] = useReducer( reducer, initialState, {type: 'reset', payload: initialCount}, ); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'reset', payload: initialCount})}> Reset </button> <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ); }
Nous pouvons également créer un contexte dans ce réducteur et l'utiliser via le hook useContext
utiliser tout au long de l'application, cela reste pour les devoirs.
Pour résumer
Les crochets sont une approche assez puissante pour résoudre l'enfer et résoudre plusieurs problèmes, mais tous peuvent être utilisés avec la même définition de transfert de lien . Déjà maintenant commencent à apparaître des collections de crochets à utiliser ou cette collection . Vous pouvez en savoir plus sur les hooks dans la documentation .