Comment utiliser une async function dans un hook useEffect avec React

author
Andréas Hanss · Dec 16, 2021
dev | 2 min
Image descriptive

Pourquoi ne peut-on pas directement utiliser async/await avec useEffect dans React ?

Il va sans dire que le hook useEffect est très pratique car il permet de déclencher des actions en fonction de changement d'état ou de props, cependant par défaut il n'est pas possible du d'utiliser facilement du code asynchrone à l'aide de la syntaxe async/await.

À première vu on pourrait être tenté de faire quelque chose de la sorte pour récupérer le contenu d'une API distante.

1
const MyFunctionnalComponent: React.FC = (props) => {
2
useEffect(async () => {
3
await loadContent();
4
}, []);
5
6
return <div></div>;
7
}

🤔 Qu'est-ce qui ne va pas avec ce morceau de code ?

Si on utilise Typescript, le compilateur doit nous sortir une erreur de la sorte :

Argument of type '() => Promise<void>' is not assignable to parameter of type 'EffectCallback'.

Regardons la signification de cette erreur en lisant la définition d'une fonction asynchrone :

Une fonction qui permet d'utiliser des instructions asynchrone avec le mot cléawait, ce qui bloquera l'execution du code tant que la Promesse après laquelle le mot cléawaitse trouve n'aura pas résolu…

React Documentation

Ok… Ça me semble bien mais… voyons la suite…

Cette fonction va également retourner une Promesse, peu importe si l'on a explicitement retourné quelque chose ou non. Dans le cas où l'on retourne une donnée, elle sera enveloppée dans le contenu de resolution de la Promese que la fonction va créer et retourner automatiquement.

React Documentation

Ouch! Vous commencez à voir le problème ? Non ? Allons voir la définition du hook  useEffect ici :

Souvent, les effets de bord créent des ressources qui nécessitent d’être  nettoyées avant que le composant ne quitte l’écran, telles qu’un abonnement ou l’ID d’une horloge. Pour ce faire, la fonction fournie useEffect peut renvoyer une fonction de nettoyage. Par exemple, pour créer un abonnement.

React Documentation

📌 Utiliser une async fonction fait retourner à la fonction de retour une Promesse au lieu d'une fonction de nettoyage.

Et c'est la raison pour laquelle le compilateur nous crie dessus en Typescript. Ce pattern est également vrai pour du Javascript sans Typescript car React n'attends pas une Promesse mais une fonction.

Comment utiliser du code asynchrone dans useEffect ?

En utilisant la technique suivante, nous serons capables d'utiliser la fonction asynchrone dans nos effets :

1
const MyFunctionnalComponent: React.FC = props => {
2
useEffect(() => {
3
// Create an scoped async function in the hook
4
async function anyNameFunction() {
5
await loadContent();
6
} // Execute the created function directly
7
anyNameFunction();
8
}, []);
9
10
return <div></div>;
11
};

Maintenant, votre code est sécurisé car vous ne renvoyez rien du tout et le compilateur a cessé de crier.

Vous pouvez également utiliser un IIFE, qui a le même effet que ci-dessus.

1
const MyFunctionnalComponent: React.FC = props => {
2
useEffect(() => {
3
// Using an IIFE
4
(async function anyNameFunction() {
5
await loadContent();
6
})();
7
}, []);
8
9
return <div></div>;
10
};