• 8 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 08/02/2024

Partagez votre state entre différents composants

C'est bien beau, nous avons nos composants avec leur state local. Notre panier permet d'ajouter des monsteras, et le total du panier se calcule en fonction.

Mais comment faire pour changer le comportement d'un composant en fonction du state d'un autre composant ? Par exemple, si je veux enfin ajouter un lien entre mon  Cart   et mon composant  ShoppingList  . Je peux créer un bouton "Ajouter au panier" dans chaque  PlantItem  ... Mais comment faire pour venir compléter mon panier en fonction ?

Faites remonter l'état et mettez-le à jour depuis vos composants enfants

Partagez votre state entre différents composants

Comme son nom l'indique, un state local… est local.  Ni les parents, ni les enfants ne peuvent manipuler le state local d'un composant (ils n’en ont pas la possibilité technique).

Dans ce cas, comment faire pour partager un élément d'état entre plusieurs composants ?

Eh bien, il faudra faire remonter ces données vers le state local du plus proche composant qui est un parent commun, et y garder le state. À partir de là, il sera possible de :

  1. Faire redescendre ces infos avec des props jusqu’aux composants qui en ont besoin.

  2. Faire « remonter » les demandes d'update toujours dans les props. Pour cela, on peut utiliser la fonction de mise à jour du state récupérée dans useState, en la passant en props aux composants qui en ont besoin.

Un composant enfant remonte une mise à jour à son composant parent
Remonter les mises à jour aux parents dans les props

Attaquons-nous donc à notre exemple.

Je commence à faire remonter  cart   dans  App.js :

function App() {
    const [cart, updateCart] = useState([])
    
    return (
        <div>
            <Banner>
                <img src={logo} alt='La maison jungle' className='lmj-logo' />
                <h1 className='lmj-title'>La maison jungle</h1>
            </Banner>
            <div className='lmj-layout-inner'>
                <Cart cart={cart} updateCart={updateCart} />
                <ShoppingList cart={cart} updateCart={updateCart} />
            </div>
            <Footer />
        </div>
    )
}

export default App

Et toujours dans  App.js   dans le JSX, je passe  cart   ainsi que  updateCart    en props :

<Cart cart={cart} updateCart={updateCart} />

...que je récupère dans  Cart.js  . Vous vous souvenez de la déstructuration ? Ça nous permet de récupérer notre prop en une ligne.

J'en profite pour supprimer mon bouton "Ajouter" dans  Cart.js.

On a donc un panier un peu vide :

function Cart({ cart, updateCart }) {
    const monsteraPrice = 8
    const [isOpen, setIsOpen] = useState(true)

    return isOpen ? (
        <div className='lmj-cart'>
            <button
                className='lmj-cart-toggle-button'
                onClick={() => setIsOpen(false)}
            >
                Fermer
            </button>
            <h2>Panier</h2>
            <h3>Total : {monsteraPrice * cart}€</h3>
            <button onClick={() => updateCart(0)}>Vider le panier</button>
        </div>
    ) : (
        <div className='lmj-cart-closed'>
            <button
                className='lmj-cart-toggle-button'
                onClick={() => setIsOpen(true)}
            >
                Ouvrir le Panier
            </button>
        </div>
    )
}

export default Cart

Du côté de  ShoppingList, je lui passe  updateCart. Je le récupère ensuite dans  ShoppingList

Je change ensuite ma liste de plantes pour avoir (toujours dans  ShoppingList.js) :

function ShoppingList({ cart, updateCart }) {
// Petite précision : categories nous vient de la partie précédente pour récupérer toutes les catégories uniques de plantes.

    const categories = plantList.reduce(
        (acc, elem) =>
            acc.includes(elem.category) ? acc : acc.concat(elem.category),
            []
    )
    
    return (
        <div className='lmj-shopping-list'>
            <ul>
                {categories.map((cat) => (
                <li key={cat}>{cat}</li>
                ))}
            </ul>
            <ul className='lmj-plant-list'>
                {plantList.map(({ id, cover, name, water, light }) => (
                    <div key={id}>
                        <PlantItem cover={cover} name={name} water={water} light={light} />
                        <button onClick={() => updateCart(cart + 1)}>Ajouter</button>
                    </div>
                ))}
            </ul>
        </div>
    )
}

export default ShoppingList

Et voilà ! Maintenant, vous pouvez updater votre panier directement en cliquant sur un bouton lié à chaque plante. 🎉

Vous voyez, ce n'est pas si compliqué, il a suffi de :

  • faire remonter notre state ;

  • faire descendre le contenu de notre state et la fonction pour l'updater ;

  • déclencher la mise à jour de notre state avec une interaction utilisateur (ici le clic sur le bouton).

Nous avons vu comment partager des éléments du state entre plusieurs composants. Dans la vidéo ci-dessous, nous allons maintenant adapter notre application pour que le panier se comporte de manière un peu plus réaliste.

L'idée ici est que notre state stocke quels types de plantes ont été ajoutés, en quelle quantité, et de mettre à jour le montant total en fonction du prix.

Alors c'est parti !

Notre panier fait maintenant une liste des articles sélectionnés, et met à jour le total en fonction des plantes sélectionnées et de leur prix. 🤩

Exercez-vous

Banner Exercez-vous

Vous allez maintenant pouvoir mettre en application ce que vous avez appris dans ce chapitre sur notre site de plantes. Comme toujours, vous trouverez la base de code sur la branche P3C2-Begin.

L'objectif ici est de reprendre notre liste de catégories et de l'améliorer avec le state. Pour cela, voilà ce que vous allez faire :

  • Créer  un composant à part,  Categories  , pour gérer les catégories.

  • Afficher la liste dans  un menu déroulant <select /> avec des <options /> :

    • chaque catégorie devient une option. Il est possible de choisir une catégorie ;

    • à la sélection d'une catégorie, seules les plantes correspondant à la catégorie sélectionnée s'affichent.

  • Créer également un bouton ayant pour label "Réinitialiser". Ce bouton permet de réinitialiser votre state, et d'afficher toutes les catégories de plantes.

Vous pouvez ajouter une option qui a pour valeur une string vide lorsqu'aucune catégorie n'est sélectionnée.

La solution se trouve sur la branche P3C2-Solution.

En résumé

  • Pour utiliser un même état entre plusieurs composants, il faut :

    • faire remonter l'état dans le composant parent commun le plus proche ;

    • puis faire descendre la variable d'état et la fonction pour mettre à jour cet état dans des props.

Dans le chapitre suivant, nous apprendrons à utiliser le hook d'effet pour choisir le moment où nous souhaitons exécuter une action, par exemple pour sauvegarder notre panier dans le localStorage de notre navigateur. Alors, rendez-vous au chapitre suivant. ☀️

Exemple de certificat de réussite
Exemple de certificat de réussite