Le hook : useState
Un Hook est une fonction qui permet d' « accocher » une des fonctionnalités React à 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)
L'emploi de useState a trois conséquences :
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" ;
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.
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>
</>
)
}

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.


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 (re-render 0.74...) puis
parce que 0.74 <1, suite l'appel à setCount avec pour log re-render : 0.88 (après le log "un de plus" et count vaut 1) puis
parce que 0.88 <1, suite l'appel à setCount avec pour log re-render : 0.44 (après le log "un de plus" et count vaut 2) puis
parce que 0.44 <1, suite l'appel à setCount avec pour log re-render : 0.95 (après le log "un de plus" et count vaut 3).
puisque 0.95 >1, il n'y a plus d'appel à setCount et la fonction-composant peut rendre son résultat : count = 3


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 va nous aider à résoudre 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>
)}
}