Nous allons modifier document.title
en fonction du nombre des produits sur la liste des courses.
Nous allons y mettre soit 'Préparez votre liste des courses' (si elle est vide), soit 'Vous avez .. produit(s) sur votre liste des courses'
Le titre devrait se mettre à jour à chaque fois ou le nombre de produits sur la liste change
// src/components/ShoppingApp.js
import React, { useState, useEffect } from "react"
/* comme avant */
const ShoppingApp = ({mode}) => {
const [shopping, setShopping] = useState(["cumin", "curry"])
/* comme avant */
useEffect(() => {
document.title =
shopping.length === 0
? `Préparez vos courses`
: `${shopping.length} produit(s) sur votre liste des courses`
})
return /* comme avant */
export default ShoppingApp
Maintenant à chaque fois que ShoppingApp
render le titre du document est modifié
Peut-on améliorer notre code ?
Nous pouvons observer qu'un changement du "mode" (mode dark / mode light) déclanche aussi la remise en place du titre (même si son texte ne change pas).
Nous pouvons passer un deuxième paramètre dans useEffect
, un array qui spécifie quand cet effect devrait être exécuté. Dans notre cas, nous voulons que le titre du document change, uniquement quand shopping
change
useEffect(() => {
document.title =
shopping.length === 0
? `Préparez vos courses`
: `${shopping.length} produit(s) sur votre liste des courses`
}, [shopping])
ou même :
useEffect(() => {
document.title =
shopping.length === 0
? `Préparez vos courses`
: `${shopping.length} produit(s) sur votre liste des courses`
}, [shopping.length])
✅
Nous avons utiliser localStorage afin d'enregistrer dans la mémoire du navigateur notre liste des courses et la récuperer à la prochaine visite (après rechargement de la page)
Un petit rappel sur localStorage
:
localStorage.setItem("colorMode", mode)
- enregistre la valeur de mode dans l'objetlocalStorage
localStorage.getItem("colorMode")
- permet de recupérer la valeur enregistrée sous la clé"colorMode"
- localStorage enregistre tout en format de
string
- afin d'enregistrer un objet nous utilisons le format JSON :
JSON.stringify(myObjet)
transforme objetmyObjet
en string format JSONJSON.parse(myJSONString)
transformemyJSONString
en objet JavaScript
Revenons à notre application, nous avons besoin d'enregister la valeur de shopping
dans localStorage
à chaque fois que shopping
change
useEffect(() => {
localStorage.setItem("myShoppingList", JSON.stringify(shopping))
}, [shopping])
✅
Nous allons besoin de la valeur stockée dans localStorage pour la passer en tant que la valeur initiale de shopping
:
const [shopping, setShopping] = useState( /* ici !! */ )
Alors :
const [shopping, setShopping] = useState( JSON.parse(localStorage.getItem('myShoppingList')) || [] )
La valeur initiale de shopping est utilisée uniquement une fois, au moment ou le component monte, pourtant l'expression JSON.parse(localStorage.getItem('myShoppingList')) || []
sera évaluée à chaque render.
Pour y rémédier et améliorer la performance, nous pouvons passer une fonction dans useState
:
const [shopping, setShopping] = useState(
() => JSON.parse(localStorage.getItem("myShoppingList")) || []
)
✅
Nous appelons cela lazy initial state ou état local initial paresseux.
const [shopping, setShopping] = useState(expensiveOperationFunction()) // pas bien 👎
par contre :
const [shopping, setShopping] = useState(() => expensiveOperationFunction()) // bien 👍
ou simplement
const [shopping, setShopping] = useState(expensiveOperationFunction) // bien 👍
Utiliser la même approche et modifier le fichier src/context/ModeContext.js
afin de profiter de localStorage pour stocker la valeur de mode
.