Le contexte React est une variable globale
En Javascript, les variables sont définies dans les définitions de fonctions.
React Context est souvent décrit comme un mécanisme permettant de gérer l'état global, agissant comme une variable partagée accessible via une arborescence de composants React. Bien que cette description soit exacte, elle simplifie à l'excès les capacités de Context. Dans cet article, nous verrons comment définir efficacement le contexte, en veillant à ce qu'il soit utilisé uniquement là où cela est nécessaire et en évitant les nouveaux rendus inutiles.
React Context fournit un moyen de transmettre des données à travers l'arborescence des composants sans avoir à transmettre manuellement les accessoires à chaque niveau. Il est créé à l'aide de React.createContext et se compose d'une paire fournisseur et consommateur. Un composant Provider fournit la valeur, et tout composant enveloppé avec le hook Consumer ou useContext peut y accéder.
Voici un exemple de base :
import React, { createContext, useContext } from "react"; const ThemeContext = createContext("light"); function App() { return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar() { return <ThemedButton />; } function ThemedButton() { const theme = useContext(ThemeContext); return <button>{`Theme: ${theme}`}</button>; } export default App;
Dans cet exemple, ThemedButton peut accéder à la valeur du thème fournie par ThemeContext.Provider sans passer explicitement les accessoires via la barre d'outils.
Bien que Context soit puissant, son utilisation sans discernement peut entraîner des problèmes de performances. Lorsque la valeur fournie par un Context.Provider change, tous les composants consommant ce contexte seront restitués. Dans les applications complexes, cela peut entraîner des rendus inutiles de composants non liés.
Scoped Context fait référence à la pratique consistant à limiter l'utilisation de Context aux seules parties de l'arborescence des composants qui en ont réellement besoin. Cette approche permet de maintenir les performances et de maintenir la structure des composants propre et compréhensible.
Envisagez des scénarios impliquant des composants composés, tels que ceux fournis par des bibliothèques comme Radix Primitives. Ces composants utilisent souvent Context en interne pour gérer l'état et les interactions. Cependant, des problèmes peuvent survenir lorsque des composants similaires sont composés ensemble, conduisant à des collisions de contexte.
Radix Primitives fournit des API hautement composables pour créer des composants accessibles. Voici un exemple :
<AlertDialog.Root> <Dialog.Root> <Dialog.Trigger /> <Dialog.Content> <AlertDialog.Trigger /> {/* note the alert trigger in dialog content */} </Dialog.Content> </Dialog.Root> <AlertDialog.Content /> </AlertDialog.Root>
Un problème se pose ici car AlertDialog est une composition de Dialog avec des fonctionnalités supplémentaires pour répondre aux exigences d'AlertDialog. Cela signifie que AlertDialog.Root est également un Dialog.Root, il fournit donc à la fois DialogContext et AlertDialogContext.
Dans cette configuration, AlertDialog.Trigger (qui est également un Dialog.Trigger) peut récupérer le mauvais contexte via useContext(DialogContext), se retrouvant avec le contexte de Dialog.Root au lieu de AlertDialog.Root. Par conséquent, cliquer sur AlertDialog.Trigger pourrait faire basculer Dialog.Content plutôt que de se comporter comme prévu.
Pour éviter de tels problèmes, Radix Primitives utilise un contexte étendu. Le contexte étendu garantit que AlertDialog.Trigger interagit uniquement avec les composants AlertDialog et ne récupère pas accidentellement le contexte d'un composant composé de manière similaire. Ceci est réalisé en créant un nouveau contexte en interne et en le transmettant au composant Dialog via un accessoire personnalisé, tel que __scopeDialog. Le composant Dialog utilise ensuite ce contexte étendu dans ses appels useContext, garantissant ainsi l'isolement.
Code source du dépôt github radix ui :
https://github.com/radix-ui/primitives/blob/dae8ef4920b45f736e2574abf23676efab103645/packages/react/dialog/src/Dialog.tsx#L69
Création de portée : Un utilitaire createScope génère un espace de noms unique pour chaque composant ou composant composé. Cela garantit que chaque ensemble de contextes est isolé et n’entre pas en conflit avec les autres.
import React, { createContext, useContext } from "react"; const ThemeContext = createContext("light"); function App() { return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar() { return <ThemedButton />; } function ThemedButton() { const theme = useContext(ThemeContext); return <button>{`Theme: ${theme}`}</button>; } export default App;
Fournisseurs de portée : lors de la création de contextes, ils sont liés à la portée. Cela lie le fournisseur et le consommateur au même espace de noms.
<AlertDialog.Root> <Dialog.Root> <Dialog.Trigger /> <Dialog.Content> <AlertDialog.Trigger /> {/* note the alert trigger in dialog content */} </Dialog.Content> </Dialog.Root> <AlertDialog.Content /> </AlertDialog.Root>
Isolement du consommateur : les hooks de portée, comme useDialogScope, garantissent que les consommateurs accèdent uniquement au contexte à partir de la portée prévue.
import { createScope } from '@radix-ui/react-context'; const [createDialogContext, useDialogScope] = createScope('Dialog');
Prévention des collisions contextuelles : en définissant la portée des contextes, des composants comme AlertDialog.Trigger peuvent toujours trouver leur contexte associé (AlertDialogContext), même lorsqu'ils sont imbriqués dans d'autres contextes.
Composition flexible : les contextes étendus permettent une composition flexible et sûre des composants, garantissant que les interactions restent prévisibles.
Réutilisabilité : les développeurs peuvent réutiliser des composants génériques (par exemple, Dialog.Trigger) dans différentes portées sans modifications.
Dans votre exemple :
AlertDialog.Root crée un AlertDialogContext étendu qui encapsule son état et ses interactions.
Nested Dialog.Root et AlertDialog.Trigger coexistent sans conflits car chacun fait référence à son contexte de portée respectif.
Ce modèle de conception est une fonctionnalité clé de Radix UI, garantissant que les hiérarchies de composants complexes fonctionnent de manière transparente, sans comportement involontaire.
https://dev.to/romaintrotard/use-context-selector-demystified-4f8e
https://github.com/radix-ui/primitives
https://react.dev/reference/react/createContext
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!