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.
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.
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 !
const withRole = ({ roleRequired }: Props) => {
const [isGranted, setGranted] = useState(false);
useEffect(() => {
isUserGranted(roleRequired).then(granted => {
setGranted(granted)
});
}, []);
return isGranted
};
|
const MyPage = (props) => {
const isGranted = withRole(« role »);
return ….
}
|
export const Granted = ({children, roleRequired}) => { const isGranted = withRole(roleRequired); return isGranted ? children : null; } |