Agence web » Actualités du digital » Comment utiliser les contextes de réaction pour gérer l’état –

Comment utiliser les contextes de réaction pour gérer l’état –

Les contextes de réaction sont une fonctionnalité qui vous aide à éliminer le forage d’étai répétitif. Les accessoires sont souvent transmis d’un composant parent à un enfant profondément imbriqué. Cela nécessite que chaque composant intermédiaire «transfère» l’accessoire au composant suivant dans l’arborescence.

Les contextes vous permettent de faire passer des accessoires dans l’arborescence sans les transmettre manuellement à chaque niveau. Ceci est particulièrement utile pour les données représentant l’état de l’application de niveau supérieur. Les paramètres utilisateur, les jetons d’authentification et les données mis en cache à partir des réponses d’API sont de bons candidats pour l’API de contexte.

Ces données sont souvent gérées par un magasin d’état dédié tel que Redux. Les contextes de React peuvent souvent être utilisés à la place. Cela supprime une quantité importante de complexité dans les applications où Redux n’est utilisé que pour conserver l’état au niveau de l’application. Au lieu de créer une action, un répartiteur et un réducteur, vous pouvez utiliser un contexte React.

Un exemple sans contexte

Une fois qu’un utilisateur s’est connecté, vous souhaiterez souvent stocker des données essentielles telles que son nom et son adresse e-mail dans l’état de votre application. Cela permet à chaque composant d’afficher des informations sur l’utilisateur sans faire un aller-retour vers votre serveur API.

Voici une façon naïve de mettre en œuvre ceci:

const UserProfileLink = ({user}) => {
    return (
        <div>
            <p>Logged in as {user.Name}</p>
            <a href="/logout">Logout</a>
        </div>
    );
};
 
const Header = ({user}) => {
    return (
        <div>
            <h1>My App</h1>
            <UserProfileLink user={user} />
        </div>
    );
}
 
const App = () => {
    const [user, setUser] = useState({
        Name: "Foo Bar",
        Email: "foobar@example.com"
    });
    return <Header user={user} />
}

Il y a trois composants dans l’application. Le plus haut niveau App Le composant garde la trace de l’utilisateur actuel dans son état. Il rend le Header composant. Header rend UserProfileLink, qui affiche le nom de l’utilisateur.

Crucialement, seulement UserProfileLink interagit réellement avec l’objet utilisateur. Header doit encore recevoir un user accessoire cependant. Ceci est ensuite transmis directement dans UserProfileLink, sans être consommé par Header.

Les problèmes avec cette approche sont exaspérés à mesure que votre arborescence de composants devient plus complexe. Vous pouvez transférer des accessoires à travers plusieurs niveaux imbriqués, même si les composants intermédiaires n’utilisent pas les accessoires eux-mêmes.

Ajout de l’API Contexts

Vous pouvez atténuer ces problèmes à l’aide de l’API Contexts. Nous pouvons refactoriser l’exemple ci-dessus pour supprimer le user accessoire de Header.

le App Le composant créera un nouveau contexte pour stocker l’objet utilisateur actuel. UserProfileLink consommera le contexte. Le composant pourra accéder aux données utilisateur fournies par le contexte. Il s’agit d’un concept similaire à la connexion d’un composant à un magasin Redux.

const UserContext = React.createContext(null);
 
const UserProfileLink = () => {
    const user = useContext(UserContext);
    return (
        <div>
            <p>Logged in as {user.Name}</p>
            <a href="/logout">Logout</a>
        </div>
    );
};
 
const Header = () => {
    return (
        <div>
            <h1>My App</h1>
            <UserProfileLink />
        </div>
    );
}
 
const App = () => {
 
    const [user, setUser] = useState({
        Name: "Foo Bar",
        Email: "foobar@example.com"
    });
 
    return (
        <UserContext.Provider value={user}>
            <Header />
        </UserContext>
    );
 
}

Cet ensemble de composants refactorisé illustre comment utiliser les contextes.

Le processus commence par créer un nouveau contexte pour la valeur que vous souhaitez rendre disponible. L’appel à React.createContext(null) définit un nouveau contexte avec une valeur par défaut de null.

le App le composant a été réécrit pour envelopper Header dans UserContext.Provider. le value prop détermine la valeur actuelle du contexte. Ceci est réglé sur le user objet maintenu en état. Tous les composants imbriqués sous le fournisseur de contexte peuvent désormais consommer le contexte et accéder à l’objet utilisateur.

Si vous essayez d’accéder au contexte à partir d’un composant qui n’est pas imbriqué dans une instance de fournisseur, le composant recevra la valeur par défaut que vous avez passée à createContext(). Cela doit généralement être évité, sauf pour les valeurs de contexte statiques qui ne changeront jamais.

L’accès à la valeur de contexte fournie est observé dans UserProfileLink. le user prop a été supprimé. Le composant utilise le hook useContext () de React pour récupérer la valeur actuelle du UserContext. Cela fournira l’objet utilisateur injecté par le App composant!

Le dernier changement concerne le Header composant. Cela n’a plus besoin de transmettre le user accessoire pour qu’il puisse être entièrement retiré. En fait, le user prop est parti de l’application entière. Il est maintenant alimenté par App dans le UserContext fournisseur, pas un composant spécifique.

Utilisation du contexte avec des composants de classe

Jusqu’à présent, nous n’avons utilisé que des contextes dans les composants fonctionnels. Les contextes fonctionnent bien ici car le useContext() hook simplifie l’accès aux données fournies dans les composants enfants.

Vous pouvez également utiliser des contextes avec des composants de classe. La méthode préférée est de définir la valeur statique contextType class à l’instance de contexte que vous souhaitez utiliser. React lira cette propriété et définira le context propriété sur les instances de composant à la valeur actuelle fournie par le contexte.

const UserContext = React.createContext({Name: "Foo Bar"});
 
class MyComponent extends React.Component {
 
    // Tell React to inject the `UserContext` value
    static contextType = UserContext;
 
    render() {
        // Requested context value made available as `this.context`
        return <p>{this.context.Name}</p>;
    }
 
}

Une autre approche consiste à rendre les enfants de votre composant dans un contexte «consommateur». Vous pouvez accéder au consommateur de chaque contexte en tant que Consumer propriété de l’instance de contexte.

Vous devez fournir un une fonction en tant qu’enfant du consommateur. La fonction sera appelée avec la valeur du contexte lors du rendu du composant.

Voici à quoi cela ressemble:

const UserContext = React.createContext({Name: "Foo Bar"});
 
class MyComponent extends React.Component {
 
    render() {
        return (
            <UserContext.Consumer>
                {user => <p>{user.Name}</p>}
            </UserContext.Consumer>
        );
    }
 
}

Utilisant contextType vous limite à un contexte par composant. Les consommateurs de contexte résolvent ce problème mais peuvent rendre la méthode de rendu de votre composant plus opaque. Aucune des deux approches n’est aussi simple que la useContext() crochet disponible pour les composants fonctionnels.

Mise à jour des valeurs de contexte

Les valeurs de contexte fonctionnent de la même manière que les accessoires. Si un enfant a besoin de mettre à jour les valeurs de contexte, ajoutez une fonction au contexte. L’enfant peut appeler la fonction pour effectuer le changement de valeur de contexte.

const UserContext = React.createContext(null);
 
const UserProfileLink = () => {
    const context = useContext(UserContext);
    return (
        <div>
            <p>Logged in as {context.user.Name}</p>
            <a onClick={() => context.logoutUser()}>Logout</a>
        </div>
    );
};
 
const Header = () => {
    return (
        <div>
            <h1>My App</h1>
            <UserProfileLink />
        </div>
    );
}
 
const App = () => {
 
    const [user, setUser] = useState({
        Name: "Foo Bar",
        Email: "foobar@example.com"
    });
 
    const contextValue = {
        user,
        logoutUser: () => setUser(null)
    }
 
    return (
        <UserContext.Provider value={contextValue}>
            <Header />
        </UserContext>
    );
 
}

Cet exemple révisé montre comment App fournit maintenant un logoutUser fonction dans le contexte. Les consommateurs de contexte peuvent appeler cette fonction pour mettre à jour le user dans le App l’état du composant, entraînant la modification de la valeur du contexte en conséquence.

Gérer les re-rendus

React rendra à nouveau tous les enfants d’un fournisseur de contexte chaque fois que le fournisseur value changements d’accessoires. Les changements de valeur sont comparés à l’aide de Object.is(), ce qui signifie que vous devez faire attention lorsque vous utilisez des objets comme fournisseur de contexte value.

const App = () => {
    return (
        <ExampleContext.Provider value={{foo: "bar"}}>
            <NestedComponent />
        </ExampleContext.Provider>
    );
}

Ce composant re-rendrait NestedComponent à chaque fois App rend. UNE Nouveau l’instance d’objet est créée pour le fournisseur value prop à chaque fois, donc React restitue les enfants du composant.

Vous pouvez résoudre ce problème en soulevant le value objet dans l’état du composant. Cela garantira le même l’objet est rendu à chaque fois:

const App = () => {
    const [obj, setObj] = useState({foo: "bar"});
    return (
        <ExampleContext.Provider value={obj}>
            <NestedComponent />
        </ExampleContext.Provider>
    );
}

Résumé

Les contextes de réaction vous aident à réduire le perçage des accessoires en fournissant un moyen de premier ordre de transmettre des données dans l’arborescence des composants. Les contextes sont une bonne alternative aux bibliothèques d’état comme Redux. Ils sont intégrés à React et gagnent du terrain parmi les projets où Redux est utilisé uniquement pour connecter des composants profondément imbriqués à une source d’état partagée.

Les contextes sont destinés aux données «globales» contenues dans votre application. Ils peuvent également contenir des données pour une sous-section spécifique de votre application. Les contextes ne sont pas censés remplacer entièrement l’état des composants locaux. Les composants individuels doivent continuer à utiliser des états et des accessoires où les données ne feront que passer de haut en bas dans un arbre imbriqué peu profondément.

★★★★★