[React 进阶系列] React Context 案例学习:子组件内更新父组件的状态
Posted GoldenaArcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[React 进阶系列] React Context 案例学习:子组件内更新父组件的状态相关的知识,希望对你有一定的参考价值。
[React 进阶系列] React Context 案例学习:子组件内更新父组件的状态
一直知道 React Context 是 React 内部实现状态管理的方法,也简单的跟着官方的案例敲了一下使用 Context 进行的渲染,不过始终因为 子组件中更新父组件父组件 这一方法的实现太过麻烦,最终还是决定使用 Redux——毕竟 Redux 虽然内部实现依靠的是 Context,但是它已经封装好了。不过最近还是想要深入的学习一下 React,也就包括其状态管理机制,正好学到一个非常干净的写法,也就借此写一篇笔记。
基础的 Context 以及 useContext hook 使用
基础实现的页面如下:
改动的文件有两个:
-
App.js
主要只是清理了一下页面,让渲染的内容简单一些,并且增加了一个子组件:
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> );
-
context.js
这是主要实现的部分,也对
themeContext
进行了简单的封装,使得其他的组件不需要每次都机械性的使用useContext(ThemeContext)
这样的代码,实现如下: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);
当然,这是一个比较偷懒的做法,没有使用 <ThemeContext.Provider value=state> ... </ThemeContext.Provider>
的方法传值,而是直接在创建的时候写死。
下一步就会对 Context 进行二次封装,实现 Provier
的部分。
二次封装 Context
这里使用一个 custom hook 去对 Context 进行一下封装,将 theme
的值存在 custom hook 的 state 中,这样就可以在之后使用 setState
的方式更新 Context 中的值。
更新内容如下:
-
App.js
只有在 App 中新增了一个对
ThemeContextProvider
的 wrapper。需要注意的是,因为在 App 中使用的
ThemeContextProvider
包裹住子组件,所以 App 中是无法获得 ThemeContext 的值,只有子组件才 ”继承“ 了 Context 中的内容。export default function App() return ( <ThemeContextProvider> <div className="App"> <Child /> </div> </ThemeContextProvider> );
-
context.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> ); ;
之后所要做的事情就是将
setTheme
这个方法传到子组件中。鉴于 Context 只能传一个 value,这里所采取的方法是再次新建一个 Context,其 value 是更新 cuttom hook 中的 set 函数。
新增 Update Context
这一步的做法,相当于对 Context 进行一个三次封装,具体变动如下:
// 之前的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>
);
;
使用 useThemeUpdate 去进行 Context 的状态变化
App.js 中的更新如下:
const Child = () =>
const themeContext = useTheme();
const updateTheme = useThemeUpdate();
return (
<div
style=themeContext
onClick=() => updateTheme( theme: "hello world" )
>
"Theme"
</div>
);
;
可以看到,更新的逻辑相对而言还是比较清晰的,最终实现效果如下:
这样看来,如果项目结构相对而言比较简单,对 Redux-Saga 的需求不是很大,直接使用 Context hook 也或许是一个不错的选择,毕竟 hooks 省去了 Context.Consumer
使用回调函数取值这样一个繁复的过程。对于 Context 进行三次封装后,可以直接使用 const someVar = useXXX();
的方法取值,以及 const updateSomeVar = useXXXUpdate();
的方法进行更新也不会显得太过繁复。
最后,如果想要省去一层 wrapper,使用这样的方式也可以:
<ThemeContext.Provider value= theme, updateTheme >
children
</ThemeContext.Provider value= theme, updateTheme >
// when you need to use it
const theme, updateTheme = useTheme();
不过这也是个人倾向,以及在不在意 typo 和自动导入提示的细节问题了,毕竟大部分时候我个人还是觉得,有自动提示/自动导入还是比较方便的。
以上是关于[React 进阶系列] React Context 案例学习:子组件内更新父组件的状态的主要内容,如果未能解决你的问题,请参考以下文章
[React 进阶系列] Functional Component 与 Class Component 中使用 Context
[React 进阶系列] Functional Component 与 Class Component 中使用 Context
[React 进阶系列] Functional Component 与 Class Component 中使用 Context