Aller au contenu principal


Le hook : useState

Un Hook est une fonction qui permet d' « accrocher » une des fonctionnalités React à un composant (une fonction-composant).

Le "hook" useState est utilisé pour gérer le changement d'état du composant (ie : les données changent au fil du temps par exemple suite à une action de l'utilisateur).

Donc, pour ajouter un état à une fonction-composant, il faut l'importer :

import React, { useState } from 'react';

Ensuite, on déclare l'état de la fonction- composant par l'appel à useState() en utilisant la syntaxe suivante :

const [state, setState] = useState(initialState)

Billet créé le :
31 mai 2022
Dernière MAJ :
18 Mar 2025

L'emploi de useState a trois conséquences :

  1. création et initialisation d'une variable (dite variable d'état pour mémoriser l'état de la fonction-composant) : dans l'exemple ci-dessous, les variables d'état sont "studentName", "course" et "colore" ;

  2. initialisation de la variable d'état avec la valeur initialState, paramètre de useState(). Dans l'exemple :

    • la variable d'état "colore" est initialisée à "blue" ;

    • la variable d'état "course" est initialisée avec une chaîne vide.

  3. création d'un setter : fonction qui met à jour la valeur la variable d'état créée. Dans l'exemple, les setter sont "setStudentName", "setCourse" et "setColoreBorderInputText" ;

Exemple : la fonction-composant Crud()

const Crud = () => {
//déclaration de l'état du composant
const [ studentName, setStudentName ]= useState("");
const [ course, setCourse ]= useState("");
const [ colore, setColoreBorderInputText ]= useState("blue");
// ...
return(
<>
<View style={styles.container, {backgroundColor:"lightcyan"}}>
{ Lire()}
</View>
<View style={styles.container , {backgroundColor:"lightcyan"}}>
{Inscrire()}
</View>
</>
)
}

Attention cependant, chaque utilisation d'un setter (exemple : setStudentName)
  • mettra à jour sa variable d'état (dans l'exemple : studentName sera mis à jour) ;

  • si la mise à jour modifie la valeur de la variable, cela provoquera un nouveau rendu ("re-chargement") de la fonction- composant.

React se rappelle de la valeur des variables d'état entre deux rendus et fournit toujours la plus récente à notre fonction-composant.

information complémentaire disponible en cliquant iciUne erreur assez classique : la boucle infinie de rendu...

Cliquer pour agrandir l'image

L'image ci-dessus est une illustration de l'erreur produite par la fonction-composant "Compteur" dont le code est affiché ci-dessous.

Le problème : le setter setCount() est invoquée lorsque le composant est rendu, il met à jour l'état, ce qui provoque un nouveau rendu. Celui-ci invoque donc le setter qui met à jour l'état, et qui provoque un nouveau rendu et cela boucle à l'infini.

Exemple de boucle infinie :

const Compteur = () => {
const[ count, setCount] = useState(0);

setCount((count) => count + 1);

return (
<View>
<Text
style={{
justifyContent: 'center',
alignItems: 'center',
marginTop: 16,
}}
>
Compteur: {count}
</Text>
</View>
)
};

Dans l'exemple ci-dessous, il n'y plus de boucle infinie car le setter n'est appelé que si une condition est remplie.

const Compteur = () => {
const[ count, setCount] = useState(0);

let i = Math.random();
console.log("re-render: " + i);
if (i < 0.9) {
console.log("un de plus");
setCount (count + 1);
};
return (
<View>
<Text
style={{
justifyContent: 'center',
alignItems: 'center',
marginTop: 16,
}}
>
Compteur: {count}
</Text>
</View>
)
};

L'illustration ci-jointe montre que 4 rendus se sont produits :

  • le 1er au chargement de la page (la console affiche :"re-render : 0.74") puis

  • parce que 0.74 < 0.9, le test i<0.9 rend "vrai", la console affiche "un de plus", il y appel à setCount avec 1 pour paramètre. La variable d'état count est mise à jour (sa valeur est maintenant 1) et il y a un nouveau rendu pour lequel la console affiche : "re-render : 0.88" ; puis

  • parce que 0.88 < 0.9, le test i<0.9 rend "vrai", la console affiche "un de plus", il y appel à setCount avec 2 pour paramètre. La variable d'état count est mise à jour (sa valeur est maintenant 2) et il y a un nouveau rendu pour lequel la console affiche : "re-render : 0.44" ; puis

  • parce que 0.44 <0.9, le test i<0.9 rend "vrai", la console affiche "un de plus", il y appel à setCount avec 3 pour paramètre. La variable d'état count est mise à jour (sa valeur est maintenant 3) et il y a un nouveau rendu pour lequel la console affiche : "re-render : 0.95" ; puis

  • puisque 0.95 >0.9, le test i<0.9 rend "faux" et la fonction-composant peut rendre son résultat : count = 3

Cliquez pour agrandir l'image

information complémentaire disponible en cliquant iciUseEffect pour gérer la boucle infinie de rendu...

Ci- dessous figure le code d'un compteur qui s'incrémente toutes les 5s (plus précisément devrait ...)

const Gps = () => {
const[ inter, setInter] = useState(5000);
const[ count, setCount] = useState(0);

const compteur = (interval) => {
console.log("debut execution compteur");

// toutes les 5s, setInterval exécute setCount pour incrémenter notre compteur
const ref = setInterval(function () {
setCount((count) => count + 1);
}, interval);
console.log("ref : " + ref + " compteur : " + count);

return ;
}

console.log(" le rendu principal");
compteur(inter);

return (
<View>
<Text>
Intervalle : {inter} et Compteur : {count} !
</Text>
</View>
);
}

L'illustration ci-dessous montre la boucle infinie de rendu

  • le 1er au chargement de la page l'appel à setInterval rends la référence 16 avec un compteur à 0 puis

  • suite l'appel à setCount un nouveau rendu se produit avec un nouvel appel à setInterval (ref : 20), le compteur est bien incrémenté

  • suite l'appel à setCount qui un nouveau rendu avec un nouvel appel à setInterval (ref : 22), le compteur est bien incrémenté

  • suite l'appel à setCount qui un nouveau rendu avec un nouvel appel à setInterval (ref : 24), le compteur est bien incrémenté

  • ...

Notre compteur est bien incrémenté mais l'intervalle entre chaque incrémentation n'est plus respecté, notre compteur s'emballe.

Le hook useEffect, présenté dans ce billet, va nous aider à résoudre ce problème.

Cliquez pour agrandir l'image

Le hook "useRef" apporte également une réponse à ce problème.

Une fonction "Lire()", présentée ici, permet d'afficher les données actuellement stockées dans une table d'une base de données.
Une fonction "Inscrire()", décrite ci-dessous permet la saisie d'un nouvel enregistrement dans cette table.

Les contrôles "TextInput" utilisent les 3 setters pour :

  • mémoriser un nom d'étudiant ;

  • mémoriser un cours ;

  • mémoriser une couleur.

const Inscrire =() => {
return(
<View>
<View style={{width:"100%", backgroundColor:"coral",}}>
<Text style={{ textAlign:"center", fontWeight :"bold",fontSize:20 }}>
- Ajouter un enregistrement -
</Text>
</View>
<TextInput
style= { [styles.input, {borderColor:colore,width:220} ]}
placeholder={"nom de l'étudiant : "}
onChangeText={setStudentName}
value={studentName}
maxLength={24}
onFocus={colore => setColoreBorderInputText("red")}
/>
<TextInput
style= { [styles.input, {borderColor:colore,width:220} ]}
placeholder={"nom du cours : "}
onChangeText={setCourse}
value={course}
maxLength={24}
onFocus={colore => setColoreBorderInputText("red")}
/>
<View style= { {width:"50%", alignSelf:"center"} }>
<Button
style= {styles.button }
title={"Enregistrer"}
onPress={InsertRecord}
/>
</View>
</View>
)}
}