Allez plus loin avec les hooks

Si vous avez suivi le premier cours, vous avez dĂ©couvert les hooks avec useState  et useEffect  . Ensemble, nous avons appris Ă  les utiliser pour faire des calls API. Et dans le chapitre prĂ©cĂ©dent, vous avez dĂ©couvert le Contexte et comment y accĂ©der simplement avec useContext  : vous commencez Ă  avoir quelques cartes en main pour utiliser les hooks dans vos applications React. 🎉

Et si je vous disais que vous pouvez créer vos propres hooks ?

Créez vos propres hooks pour simplifier votre code

Je ne sais pas ce que ça Ă©voque pour vous, mais moi la premiĂšre fois qu'on m'a dit que je pouvais crĂ©er mes propres hooks, ça m’a un peu fait paniquer. Je m’imaginais devoir travailler sur la codebase de React, et devoir crĂ©er un de ces fichiers immenses pour pouvoir faire tourner un hook “custom”.

DĂ©trompez-vous, la crĂ©ation d’un hook “custom” est toute simple : il s’agit juste d’une fonction qui commence par “use”, qui extrait de la logique rĂ©utilisable et qui peut utiliser d’autres hooks.

Mettons en application ce que nous avons vu dĂšs maintenant.

Créez un hook pour vos calls API

Dans le premier chapitre, vous avez appelĂ© l’API du projet Shiny pour rĂ©cupĂ©rer les profils des freelances, ainsi que les questions de notre questionnaire.

Si vous regardez votre code d’un peu plus prĂšs, vous aussi vous voyez une certaine rĂ©pĂ©tition ? C’est normal. On va donc essayer de mutualiser tout ça avec un hook “personnalisĂ©â€Â !

Pour cela, on crĂ©e dans /utils  un nouveau dossier qu’on appelle /hooks  et dans lequel on crĂ©e un ficher index.jsx  .

On va créer notre hook qu'on base cette fois-ci sur la syntaxe async  / await  :

import { useState, useEffect } from 'react'

 

export function useFetch(url) {

const [data, setData] = useState({})

const [isLoading, setLoading] = useState(true)

 

useEffect(() => {

if (!url) return

async function fetchData() {

const response = await fetch(url)

const data = await response.json()

setData(data)

setLoading(false)

}

setLoading(true)

fetchData()

}, [url])

 

return { isLoading, data }

}

Le code est plutît explicite, n’est-ce pas ? Pour notre nouveau hook, useFetch  , on lui passe en paramùtre l’URL de l’API qu’on veut appeler. Il possùde un state interne qui lui permet de stocker la data, et de savoir si la data est en train de charger avec isLoading  .

Dans useEffect  , le hook fait un return  vide si le paramĂštre de l’URL est vide, et commence par mettre isLoading  à true  . Il dĂ©clare la fonction asynchrone fetchData  qui permet de :

  • appeller fetch  ;

  • parser ce qui est retournĂ© avec data.json()  ;

  • et changer l’état de isLoading  .

url  fait partie du tableau de dĂ©pendances du useEffect  , ce qui permettra de redĂ©clencher le call en cas de changement d’URL passĂ©e en paramĂštre. Puis, on appelle notre fonction fetchData  .

Pour utiliser notre nouveau hook, modifions /Survey/index.jsx  . On commence par importer notre hook avec :

import { useFetch } from '../utils/hooks'

Puis on récupÚre notre data avec :

const { data, isLoading } = useFetch(`http://localhost:8000/survey`)

const { surveyData } = data

Je vous invite aussi à supprimer tout le contenu du useEffect  qui permettait d’effectuer le fetch  . J’adore supprimer du code inutile : c’est super satisfaisant, non ? 😍

On n’oublie pas de remplacer isDataLoading  par isLoading  qui sera plus gĂ©nĂ©rique ici, et de remplacer surveyData  par data  .

Est-ce que ça marche toujours ?

... Oh, on a une erreur qui empĂȘche le code de tourner ! 😭

Pas de panique, c’est normal ! Pour faire la navigation, on a accĂ©dĂ© au contenu de notre objet de questions en faisant data[questionNumber]  . Sauf qu’à l’initialisation, data  est un objet vide... Ce qui veut dire qu'avec :

const { surveyData } = data

surveyData  est undefined. JavaScript provoque donc une erreur pour data[questionNumber]  . Une des maniĂšres d’éviter l’erreur est donc de vĂ©rifier que surveyData  est dĂ©fini avant de l'utiliser dans le composant :

<QuestionContent>

{surveyData && surveyData[questionNumber]}

</QuestionContent>

Et voilĂ , notre page fonctionne Ă  nouveau comme avant, en utilisant notre hook useFetch  , ce qui a permis de supprimer pas mal de code rĂ©pĂ©titif ! 🎉

Ajoutez une gestion d’erreur

Mais que se passe-t-il quand l’API nous renvoie une erreur ? Notre application ne se comportera pas comme prĂ©vu, et l’utilisateur n’en sera mĂȘme pas informĂ©. Je vous propose d’intĂ©grer une gestion d’erreur dans notre hook useFetch  afin d'afficher Ă  l'Ă©cran qu'il y a eu un problĂšme.

Pour cela, dans utils/hooks/index.jsx  , on peut créer un state pour error avec :

const [error, setError] = useState(false)

Puis, on ajoute un try  et un catch à notre cher hook useFetch  :

export function useFetch(url) {

const [data, setData] = useState({})

const [isLoading, setLoading] = useState(true)

const [error, setError] = useState(false)

 

useEffect(() => {

if (!url) return

setLoading(true)

async function fetchData() {

try {

const response = await fetch(url)

const data = await response.json()

setData(data)

} catch (err) {

console.log(gerr)

setError(true)

} finally {

setLoading(false)

}

}

fetchData()

}, [url])

return { isLoading, data, error }

}

Ce qui nous permet de passer error  à true  lorsqu'un problÚme est rencontré.

De la mĂȘme maniĂšre, dans Survey.jsx  , on rĂ©cupĂšre maintenant error  :

const { data, isLoading, error } = useFetch(`http://localhost:8000/survey`)

Et on peut tout simplement ajouter au-dessus du return  :

if (error) {

return <span>Il y a un problĂšme</span>

}

Et voilĂ , vous avez mĂȘme gĂ©rĂ© les erreurs d’appel API ! 🎉

Nous allons en profiter pour utiliser useFetch  pour envoyer les réponses de l'utilisateur, et donc récupérer les résultats de notre API depuis la page /results  .

Je vous montre tout ça dans le screencast juste en dessous. 👇

C'est pas mal ce useFetch  , je vais pouvoir l'implémenter dans toutes les bases de code en production ?

Le hook useFetch  que nous avons codĂ© ici est trĂšs pratique pour Ă©viter de nous rĂ©pĂ©ter
 et pour pratiquer la crĂ©ation de hooks personnalisĂ©s. Mais dans les faits, ce code est un peu trop basique pour ĂȘtre utilisĂ© en production. À la place, vous pouvez utiliser un outil bien plus robuste tel que TanStack Query pour React , qui vous permet d'utiliser des hooks pour faire vos requĂȘtes et les mettre en cache dans vos applications.

MaĂźtrisez les hooks

Intégrez les rÚgles des hooks

Je le rappelle ici : les hooks ont leurs propres rùgles d’utilisation.

  • Les hooks sont uniquement accessibles dans un composant fonction React. Donc ce n'est pas possible d’en utiliser dans un composant classe ou bien dans une simple fonction JavaScript.

  • Appelez les hooks au niveau racine de vos composants.

  • Attention au nommage de vos hooks personnalisĂ©s : mĂȘme s’il ne s’agit pas vraiment d’une rĂšgle obligatoire, mais d’une convention, vos hooks personnalisĂ©s doivent commencer par use  pour que l’on sache en un coup d’Ɠil qu’il s’agit d’un hook.

Pour l’instant, voici quelques hooks que vous pourriez ĂȘtre susceptible de croiser dans diffĂ©rentes codebases :

useRef

Je vous laisse regarder par vous-mĂȘme sur la documentation si ça vous intĂ©resse, mais mĂȘme s’il existe plusieurs utilisations de  useRef  , ce hook est avant tout utilisĂ© pour interagir avec des Ă©lĂ©ments du DOM.

useReducer

useReducer permet de mieux gĂ©rer votre state lorsqu’il comporte de nombreuses propriĂ©tĂ©s qui doivent ĂȘtre modifiĂ©es rĂ©guliĂšrement.

useMemo et useCallback

Ces deux hooks nous permettent d’éviter de refaire des calculs coĂ»teux pour nos performances. Vous pouvez prĂ©ciser des valeurs pour lesquelles il faudra refaire les calculs uniquement si l’un des paramĂštres change, grĂące à useMemo  et useCallback  .

Et il en existe encore d’autres
 À l’heure oĂč ce cours a Ă©tĂ© Ă©crit, nous en sommes Ă  la version 17 de React. Mais nous ne sommes pas Ă  l’abri que d’autres hooks soient créés entretemps.

Exercez-vous

Maintenant que nous avons créé un hook personnalisĂ© pour faire des calls API useFetch  , vous allez pouvoir l’utiliser pour les pages /Freelances  ainsi que /Results  .

Vous allez également devoir créer un hook personnalisé useTheme  qui récupÚre le Contexte du theme  et vous permet de récupérer le thÚme actuel (  dark  ou light  ).

À partir de lĂ , vous pouvez intĂ©grer les changements de style pour le thĂšme, et intĂ©grer la page /results  en fonction des maquettes si vous voulez vous challenger (ou rĂ©cupĂ©rer le CSS sur la branche solution si vous prĂ©fĂ©rez passer moins de temps sur le CSS).

Comme d’habitude, vous trouverez le dĂ©but de l’exercicesur la branche P2C3-beginet la solutionsur P2C3-solution .

En résumé

  • Un hook personnalisĂ© est une fonction qui commence par “use”, qui extrait de la logique rĂ©utilisable et qui peut utiliser d’autres hooks. 

  • Les rĂšgles des hooks s’appliquent aux hooks personnalisĂ©s, en plus de la convention de nommer son hook personnalisĂ© avec  use...   .

  • Il existe d’autres hooks tels que useRef  , useReducer  , useMemo  , etc.

Bon, votre application commence vraiment Ă  ressembler Ă  quelque chose ! J’espĂšre que cet aperçu un peu plus poussĂ© des hooks vous a bien plu. Mais comment vous assurer de ne pas tout casser si vous faites des modifications dans 6 mois
 ou un an, alors que vous ne vous souvenez plus comment votre code est implĂ©menté ? Eh bien
 par les tests. C'est ce que nous allons voir dans la prochaine partie. Mais avant cela, vous allez pouvoir tester vos connaissances dans un quiz. Alors bonne chance Ă  vous, et on se retrouve dans quelques instants ! đŸ’Ș

Ever considered an OpenClassrooms diploma?
  • Up to 100% of your training program funded
  • Flexible start date
  • Career-focused projects
  • Individual mentoring
Find the training program and funding option that suits you best