[Série React Advanced] Étude de cas React Context : Mise à jour de l'état du composant parent dans le composant enfant
J'ai toujours su que React Context est la méthode d'implémentation de la gestion d'état dans React, et j'ai simplement suivi le cas officiel pour exploiter le rendu à l'aide de Context, mais c'est toujours parce que l'implémentation de la méthode de mise à jour du composant parent du composant parent dans le composant enfant est trop gênant, et finalement Still a décidé d'utiliser Redux - après tout, bien que l'implémentation interne de Redux repose sur Context, elle est déjà encapsulée. Cependant, je veux encore en savoir plus sur React récemment, y compris son mécanisme de gestion d'état.Je viens d'apprendre une manière très propre d'écrire, alors j'ai écrit une note.
Contexte de base et utilisation du hook useContext
La page de mise en œuvre de base est la suivante :
Deux fichiers ont été modifiés :
-
App.js
L'essentiel est de nettoyer la page, de simplifier le rendu du contenu et d'ajouter un sous-composant :
import { useTheme } from "./context"; import "./styles.css"; const Child = () => { const themeContext = useTheme(); return <div style={ themeContext}> "Theme" </div>; }; export default function App() { return ( <div className="App"> <Child /> </div> ); }
-
contexte.js
Il s'agit de la partie principale de l'implémentation,
themeContext
et encapsule simplement , de sorte que les autres composants n'ont pas besoin d'utiliser mécaniquementuseContext(ThemeContext)
ce code à chaque fois. L'implémentation est la suivante :import React, { useContext } from "react"; const theme = { dark: { backgroundColor: "#333", color: "#ccc", padding: "2em", margin: "2em", }, light: { backgroundColor: "#ccc", color: "#333", padding: "2em", margin: "2em", }, }; const ThemeContext = React.createContext(theme.dark); export const useTheme = () => useContext(ThemeContext);
Bien sûr, il s'agit d'une approche relativement paresseuse. Au lieu d'utiliser <ThemeContext.Provider value={state}> ... </ThemeContext.Provider>
la méthode pour transmettre des valeurs, elle est directement écrite à mort lors de sa création.
La prochaine étape sera l'encapsulation secondaire de Context, la réalisation Provier
de la pièce.
Encapsulation secondaire du contexte
Ici, un crochet personnalisé est utilisé pour encapsuler le contexte et theme
la valeur de est stockée dans l'état du crochet personnalisé, de sorte setState
que la valeur dans le contexte puisse être mise à jour ultérieurement à l'aide de la méthode.
Les mises à jour sont les suivantes :
-
App.js
Seule une paire
ThemeContextProvider
d' .Il convient de noter que, comme le sous-composant est
ThemeContextProvider
encapsulé l'App, la valeur de ThemeContext ne peut pas être obtenue dans l'App, et seul le sous-composant "hérite" du contenu du Context.export default function App() { return ( <ThemeContextProvider> <div className="App"> <Child /> </div> </ThemeContextProvider> );
-
contexte.js
import React, { useContext, useState } from "react"; // 因为变量名冲突的关系,这里将其改成了大写……不过常量大写也比较正常 const THEME = { dark: { backgroundColor: "#333", color: "#ccc", padding: "2em", margin: "2em", }, light: { backgroundColor: "#ccc", color: "#333", padding: "2em", margin: "2em", }, }; const ThemeContext = React.createContext(); export const useTheme = () => useContext(ThemeContext); export const ThemeContextProvider = ({ children }) => { const [theme, setTheme] = useState(THEME.dark); return ( <ThemeContext.Provider value={ theme}>{ children}</ThemeContext.Provider> ); };
Tout ce que nous avons à faire après cela est de passer
setTheme
cette méthode au composant enfant.Étant donné que Context ne peut transmettre qu'une seule valeur, la méthode adoptée ici consiste à créer à nouveau un nouveau Context, dont la valeur est de mettre à jour la fonction set dans le crochet cuttom.
Contexte de mise à jour ajouté
Cette étape équivaut à encapsuler le contexte trois fois. Les modifications spécifiques sont les suivantes :
// 之前的THEME没有变化
const ThemeContext = React.createContext();
const ThemeUpdateContext = React.createContext();
export const useTheme = () => useContext(ThemeContext);
export const useThemeUpdate = () => useContext(ThemeUpdateContext);
export const ThemeContextProvider = ({
children }) => {
const [theme, setTheme] = useState(THEME.dark);
const updateTheme = ({
theme }) => {
// 这里只是做一个传值的示范
console.log(theme);
setTheme((prevTheme) =>
prevTheme === THEME.dark ? THEME.light : THEME.dark
);
};
return (
<ThemeContext.Provider value={
theme}>
<ThemeUpdateContext.Provider value={
updateTheme}>
{
children}
</ThemeUpdateContext.Provider>
</ThemeContext.Provider>
);
};
Utilisez useThemeUpdate pour changer l'état du contexte
La mise à jour dans App.js est la suivante :
const Child = () => {
const themeContext = useTheme();
const updateTheme = useThemeUpdate();
return (
<div
style={
themeContext}
onClick={
() => updateTheme({
theme: "hello world" })}
>
"Theme"
</div>
);
};
On peut voir que la logique de mise à jour est relativement claire et l'effet final de la mise en œuvre est le suivant :
De ce point de vue, si la structure du projet est relativement simple et que la demande pour Redux-Saga n'est pas très importante, il peut être judicieux d'utiliser directement le crochet de contexte.Après tout, les crochets évitent le processus compliqué d' Context.Consumer
utilisation des fonctions de rappel pour obtenir des valeurs. . Après avoir encapsulé le contexte trois fois, vous pouvez directement utiliser const someVar = useXXX();
la méthode pour obtenir la valeur, et const updateSomeVar = useXXXUpdate();
la méthode pour la mettre à jour ne sera pas trop compliquée.
Enfin, si vous souhaitez enregistrer une couche de wrapper, vous pouvez également utiliser cette méthode :
<ThemeContext.Provider value={
{
theme, updateTheme }}>
{
children}
</ThemeContext.Provider value={
{
theme, updateTheme }}>
// when you need to use it
const {
theme, updateTheme } = useTheme();
Cependant, c'est aussi une tendance personnelle, et je ne me soucie pas des détails des fautes de frappe et des invites d'importation automatiques.Après tout, la plupart du temps, je pense toujours qu'il est plus pratique d'avoir des invites automatiques/importation automatique.