Loupe

Les hooks suite et fin - Ce que font les librairies populaires de React

Suite aux deux précédents articles sur les Hooks que vous pouvez retrouver ici et ici, je me suis dit que ça serait bien de clôturer cette série en regardant ce qui se fait du côté des grosses librairies de Reactjs et comment celles-ci implémentent des customs Hooks pour faciliter et améliorer l’intégration de ces librairies dans un projet React.

React Router et useParams()

Nous allons tout d’abord parler de la dernière mise à jour de React Router qui est l’une des librairies les plus utilisées dans le monde React. Elle permet d’ajouter un router dans react et de pouvoir ainsi contrôler la navigation de l’utilisateur dans une application.

Lors de la dernière mise à jour majeure de la librairie (la 5.1) et à l'arrivée des Hooks dans React, l’équipe de React Router a déclaré qu'ils souhaitaient intégrer à leur tour des Hooks développés en interne afin de rendre l’utilisation de la librairie plus simple et palier à certains soucis inhérents à React. A noter que pour l’instant les nouveaux Hooks de React Router coexistent parfaitement avec l’existant et n’induisent pas de Breaking changes, ce qui sera cependant le cas dans le futur puisque l’équipe de la librairie a l’intention de ne garder que les Hooks. La team React encourage donc les utilisateurs à désormais utiliser au maximum les Hooks dès maintenant afin d’avoir le moins de migrations à faire dans le futur.

Dans React Router, la possibilité de récupérer les paramètres d’une url quelconque se fait via la prop match injecté dans notre composant comme ceci :

class MyRouteComponent extends React.Component {
    constructor(props) {
	    super(props);

		console.log(this.props.match);
	}
}

Il y a ensuite deux façons d’appeler ce composant via le routing afin de de lui injecter la prop match :

<Route path="/my-route-component" component={MyRouteComponent} />

Ou

<Route
    path="/my-route-component"
    render={({match}) => <MyRouteComponent match={match}/>}
/>

L’avantage avec la deuxième manière est qu’elle nous autorise à passer des props supplémentaires à notre composant, ce qui n’est pas possible avec la première manière.

Avec useParams, les choses deviennent plus simples :

const MyRouteComponent = () => {
    const params = useParams();
}

Et il n’y a désormais plus qu’une seule façon d’appeler notre route :

<Route path="my-route-component">
    <MyRouteComponent />
</Route>

Tada ! On se retrouve avec le meilleur des cas possibles :

  • Au niveau du Routing, on a l’affichage le plus simple possible avec une arborescence de dom JSX classique, pas de props component ni de props render.
  • Au niveau du composant de route, on ne reçoit plus de props de la part de React Router, on gagne donc en lisibilité et simplicité.
  • Le dernier avantage et le plus important est que le composant de route appelle useParams si et seulement s’il souhaite récupérer la prop match. Cela sous-entend que seuls les composants qui souhaitent récupérer la prop match appellent useParams. Ainsi, si l’un des enfants de notre composant de route souhaite également accéder à cette prop, il aura juste à appeler useParams. Sans Hooks, nous aurions dû faire descendre la prop jusqu’au composant en question, cela permet de ne plus s’embêter avec l’arborescence de passage de props.

Les autres Hooks apportés par React Router 5.1 suivent le même procédé. Les données transmises par React Router étant des informations de navigation, les Hooks pour l’instant proposés par React Router ont pour but de nous éviter de devoir passer de parent à enfant toutes ces données via l’arborescence de composants.

Pour la liste des Hooks implémentés dans la 5.1 de React Router, c’est ici.

React Redux

Compliqué de parler de librairie majeure de React sans parler de React Redux, et ça tombe bien puisque, depuis la version 7.1 de la librairie, des Hooks ont été mis en place pour nous simplifier l’implémentation que l’on sait assez fastidieuse de Redux.

En effet, afin d’avoir accès au store depuis nos composants React, il suffit ordinairement de passer par la fonction connect fournie par Redux qui nous permet de récupérer les valeurs qui nous intéressent, ainsi que les fonctions nous permettant de dispatch des actions Redux.

Les Hooks Redux sont là avec un objectif principal : se passer de connect.

A noter que pour avoir accès aux Hooks, il est toujours nécessaire d’encapsuler notre App avec le composant Provider fourni par Redux.

useSelector()

useSelector va nous permettre de récupérer une valeur du store Redux. Le Hook prend 2 arguments : selector: Function qui sera notre selector Redux et equalityFn?: Function qui sera une fonction de comparaison qui retourne un booléen indiquant si la nouvelle valeur retournée est identique à la précédente fois où ce même useSelector a été appelé.

Ainsi, pour récupérer le nom d’un utilisateur connecté :

import { useSelector } from  'react-redux';

export const DisplayNameComponent = () => {
    const name = useSelector(state => state.user.name);
    
    return  <div>Currently connecter user : {name}</div>
}

A la manière d’un mapStateToProps, le selector prend en argument le state Redux et retourne la valeur demandée.

Plusieurs choses sont à savoir afin de ne pas avoir de soucis d’optimisation :

  • useSelector est appelé à chaque fois que le composant est rendu et à chaque fois qu’une action est dispatch.
  • Chaque appel à useSelector crée une nouvelle souscription au store Redux.
  • Si la valeur ne change pas par rapport au précédent appel, cela ne déclenche pas un nouveau rendu du composant. Cependant, la comparaison se faisant via référence stricte ===, une valeur de type Object sera donc toujours considérée comme une nouvelle valeur due au changement de référence. Pour cela, la team Redux conseille soit de renvoyer des variables simples et d’utiliser autant de useSelector que de variables demandées, soit d’utiliser la fonction shallowEqual fournie par Redux et de la passer en second argument de useSelector.

useDispatch()

Ce Hook permet simplement de récupérer la fonction dispatch au sein de notre composant afin de pouvoir dispatch des actions Redux.

Par exemple, pour mettre à jour le nom de l’utilisateur connecté :

const  ChangeNameComponent  =  ()  =>  {
    const  dispatch  =  useDispatch();
    
    return  <input onChange={(ev) =>  dispatch({ type:  'CHANGE_NAME', value:  ev.target.value})} />
}

Et c’est tout pour React Redux ! Vous pouvez retrouver la documentation détaillée des Hooks dans Redux ici. A savoir que l’équipe est visiblement en développement sur d’autres Hooks pour le futur de Redux. Stay tuned donc ! :)

React Hook Form

Petit bonus, j’avais prévu d’arrêter cet article ici mais, dans ma veille, je suis tombé sur cette petite librairie de formulaires entièrement codée avec des Hooks. Les développeurs mettent en avant le caractère rapide et léger de la librairie par rapport aux librairies concurrentes de réalisation de formulaires avec des benchmarks et autres comparatifs. C’est assez sympa, j’invite les curieux à y faire un tour :)

Conclusion

Nous arrivons donc à la fin de cet article et de cette série sur les Hooks dans React ! Nous avons pu voir dans le premier article une brève introduction sur leur apparition dans le monde React et une utilisation basique des plus importants d’entre eux. Puis nous avons vu dans le deuxième article quelques cas d’utilisation ainsi que des conseils / retours personnels basé sur l’utilisation que j’ai pu en faire au quotidien et nous terminons donc aujourd’hui par cet article qui montre comment certaines grosses librairies de React se servent de ce nouvel ajout au framework.
Vive les Hooks !

Happy Coding ! :-)

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus