Dans l'article précédent, je montrais le pattern Getter Components (un nom totalement inventé) pour contourner les Rules of Hooks. Pratique dans le cas où vous ne pouvez pas appeler de hooks sans respecter leurs règles.
Mais ce n'est pas la seule manière de les contourner ! J'utilise régulièrement un seconde astuce : retourner un getter plutôt que la valeur.
Reprenons l'exemple du post précédent. Nous avions :
- un hook
usePicture(id: string): Picture
- un component
ArticleList
qui doit afficher une liste deArticle
- et pour chaque
Article
, ce component affiche une image si l'attributcoverPictureId
duArticle
n'est pasnull
Soit, en code :
type Article = {
id: string
title: string
coverPictureId: string | null
}
type Picture = {
id: string
src: string
}
declare function usePicture(id: string): Picture
function ArticleList({ articles } { articles: Article[] }) {
return (
<ol>
{articles.map(article => (
<li key={article.id}>
{article.coverPictureId && (
<img src={/* TODO: obtenir le bon src ici */} />
)}
{article.title}
</li>
)}
</ol>
)
}
Le problème est le même que dans l'article précédent : notre img
étant dans une boucle (.map
) et un conditionnel (&&
), impossible d'utiliser notre hook usePicture
pour obtenir le bon src
.
En fait, une solution plutôt élégante est de changer la signature de notre hook pour qu'il ne retourne plus une valeur, mais une fonction permettant d'obtenir une valeur.
Un getter quoi.
Donc, usePicture(id: string): Picture
peut devenir useGetPicture(): (id: string) => Picture
.
Et il devient ainsi possible de rendre l'appel au hook inconditionnel, mais d'utiliser la fonction dans l'itération ou le conditionnel tout en respectant les règles des hooks.
Notre component devient alors :
function ArticleList({ articles } { articles: Article[] }) {
const getPicture = useGetPicture()
return (
<ol>
{articles.map(article => (
<li key={article.id}>
{article.coverPictureId && (
<img src={getPicture(article.coverPictureId).src} />
)}
{article.title}
</li>
)}
</ol>
)
}
✅ Simple
✅ Basique
À noter : c'est mon go-to pour contourner les règles des hooks, mais cette solution a une grosse contrainte. Elle est "contaminante". Par exemple, elle n'est pas compatible avec React Query puisqu'il est impossible de fetcher une query dans une fonction.
Pour ces cas là, j'utilise donc toujours les Getter Components.
Hapy coding ✌️