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 ?
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.
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 } = dataJe 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 } = datasurveyData 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 ! đ
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.
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 :
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 permet de mieux gĂ©rer votre state lorsquâil comporte de nombreuses propriĂ©tĂ©s qui doivent ĂȘtre modifiĂ©es rĂ©guliĂšrement.
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.

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 .
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 ! đȘ