Comment transformer un higher order component en React Hook

par | Mai 29, 2019

Aujourd’hui, dans cet article, nous allons voir comment remplacer le pattern Higher Order Component par React Hook. Au sein de cet article, vous trouverez les avantages et inconvénients de chacun de ces deux outils.

Higher Order Component

Le HOC est un pattern permettant d’encapsuler un composant et d’en modifier le comportement sans toucher au composant encapsulé ou en injectant des propriétés calculées par le HOC. En clair, le HOC est une fonction qui retourne un composant dont le comportement est modifié par celui-ci.

 

Un exemple avec un HOC qui n’affiche le composant que si l’utilisateur a les droits nécessaires :

const withRole = (WrappedComponent, roleRequired) =>{ return class extends React.Component { constructor(props){ super(props); this.state = { granted: false }; } componentDidMount() { isUserGranted(roleRequired).then(granted =>; {
this.setState({ granted });
});
}
render(){
const { granted } = this.state;
return granted ? : null;
}
};
};

Pour l’utiliser il suffit de wrapper le composant :

const GrantedView = withRole(AwesomeView, ‘<role_required>’);

On identifie tout de suite le problème, si on veut définir plusieurs HOC on obtient :

 withAuthentication(withRole(withUser(WrappedComponent)));

Pas de soucis, compose à la rescousse :

const UserComponent = compose(
withAuthentication,
withRole,
withUser,
);

Mais en plus d’être verbeux, cela génère une hiérarchie telle que :

<withAuthentication>
<withRole>
<withUser>
<UserComponent/>
</withUser>
</withRole>
</withAuthentication>

Il y a un donc non seulement une complexité non négligeable pour un simple isGranted et cette complexité au niveau de la hiérarchie a un impact direct sur la performance. A noter qu’un HOC a parfaitement sa place pour un isAuthenticated par exemple dans un router. Mais dans notre cas on va simplifier notre HOC pour le rendre encore plus réutilisable avec des hooks.

React Hook

Les règles à respecter pour des hooks fonctionnels :
https://reactjs.org/docs/hooks-rules.html

Si une de ces règles n’est pas respectée, un comportement inattendu peut survenir dans l’application.

Comme pour le Higher Order Component, le principe est de modifier/surcharger le comportement d’un composant, sans tomber dans le piège du high order component hell et du nesting hell, sauf que cette fois c’est le composant lui même qui appelle le hook, et c’est ce hook qui contiendra la logique.

Comme pour le HOC, React Hook possède quelques inconvénients. Premièrement, l’appropriation des connaissances pour concevoir un Hook. Les hooks sont maintenant bien assimilés par la communauté, mais si vous n’en avez encore jamais fait, écrire votre premier custom hook peut vous donner des boutons !
“Passer des classes à … ça ?!”
Le principal inconvénient des hooks, c’est le couplage fort (composition) entre le composant qui l’utilise et le hook. Regardons ça !

Transformer un HOC en React Hook

On va donc créer un custom Hook, qui va se charger de faire l’appel API isUserGranted, et nous retourner la réponse. Ce hook impacte directement le cycle de vie du composant qu’il implémente :

const withRole = ({ roleRequired }: Props) => {
const [isGranted, setGranted] = useState(false);
useEffect(() => {
isUserGranted(roleRequired).then(granted => {
setGranted(granted)
});
}, []);
return isGranted
};

Je peux utiliser le hook directement :

const MyPage = (props) => {
const isGranted = withRole(« role »);
return ….
}

Ou encore l’utiliser pour faire un composant qui affichera ou pas son enfant en fonction de la résolution de la variable isGranted :

export const Granted = ({children, roleRequired}) => { const isGranted = withRole(roleRequired); return isGranted ? children : null; }

On a utilisé ici un hook react : useEffect, qui est l’équivalent du componentDidMount(). Le component MyPage, sera de nouveau “rendu” lorsque la variable isGranted sera résolue par notre web-service. Le premier avantage, c’est la simplicité. C’est lisible, toute la complexité inutile a disparu. La hiérarchie est plate, pas de composant supérieur à l’horizon. Cependant il y a un inconvénient, que l’on a pas avec les HOC, le couplage fort. La communauté React est bien au courant de ce défaut, maintenant nous utilisons les hooks de manière générale, ces hooks vont surement évoluer à l’avenir.

Des bonnes raisons d’utiliser un HOC au lieu d’un Hook :

  • Il ne génère pas plus d’une props a passer au composant encapsulé.
  • Il ne crée pas de dépendances implicites ( un ordre particulier dans les HOC par exemple ).
  • Un comportement par défaut doit être partagé sur plusieurs components.

C’est ainsi que se termine notre article sur la transformation d’un HOC en React Hook.

0 commentaires

Soumettre un commentaire

Votre adresse de messagerie ne sera pas publiée.

Vous apprécierez aussi (probablement)