在前不久的一篇文章 React 开发 - 认识Zustand 中,我们了解了通过 Zustand
进行状态管理。这篇文章,我们直接来学习通过 createContext
来进行组件树的状态管理。
React.createContext
是用于创建上下文,方便组件树中共享数据,而不需要通过 props
逐层传递数据。
用法
使用它也是很简单:
- 创建上下文 -
createContext
- 使用
Provider
提供上下文 - 使用
useContext
钩子消费上下文
tsx 代码解读复制代码// demo.jsx
import React, { createContext, useContext } from "react";
import { ChildComponent } from "path/to/ChildComponent.tsx";
// 1. 创建上下文对象
const MyContext = createContext(null);
function Demo() {
const value = { name: "Jimmy", address: "Canton"};
return (
// 2. 使用 Provider 提供上下文
<MyContext.Provider value={ value }>
<ChildComponent />
MyContext.Provider>
);
}
上面是父组件,下面我们来编写消费的子组件 ChildComponent
,如下:
tsx 代码解读复制代码// ChildComponent.tsx
function ChildComponent() {
// 3. 使用 useContext 钩子来消费上下文值
const value = useContext(MyContext);
return (
<div>
<p>Name: {value.name}p>
<p>Address: {value.address}p>
div>
);
}
上面我们通过一个简单的案例已经了解了怎么使用它。下面,我们通过一个详细的案例来熟悉它。
案例
假设我们需要在父组件中传递数据给子组件,然后,在子组件的各个地方都能够 dispatch
数据回传到父组件进行处理。
在进入正文之前,我们有必要了解下 React.useReducer
这个钩子函数。
useReducer
是 React
提供的用于管理组件的状态的钩子函数,类似于 useState
,但是更加适合处理复杂的状态逻辑。
useReducer
接受三个参数:
- reducer: 一个函数,用于处理状态更新逻辑。它接受当前状态和一个
action
对象,并且返回新的状态。如下例子中的shootReducer
- initialState:初始状态
- init: 可选,一个函数,用于惰性初始化状态
什么叫做惰性初始化。惰性初始化意味着初始状态的计算会被延迟到组件首次渲染时进行,而不是在定义
useReducer
时立即计算。这种方式可以提高性能,特别是当初始状态的计算比较复杂或者依赖于某些异步的操作时。当传入第三个参数的时候,第二个参数的意义就没那么重要了
嗯~进入正题。我们有下面的父组件👇
tsx 代码解读复制代码const noop = () => {}
// 接口 action
interface IShootAction {
type: "updateShootCount" | "updateCountDown"
}
// 接口 state
interface IShootState {
shootCount: number;
countDown: number;
}
// 上下文
export const ShootContext = React.createContext({
shootCount:1,
countDown: -1,
dispatch: noop as React.Dispatch<IShootAction>
});
// 更改 state
function shootReducer(state: IShootState, action: IShootAction): IShootState {
switch (action.type) {
case "updateShootCount":
state.shootCount = action.shootCount ?? state.shootCount;
break;
case "updateCountDown":
state.countDown = action.countDown ?? state.countDown;
break;
}
return { ...state };
}
// 父函数组件
export const ShootView: React.FC = () => {
const operate = "paperwork";
// useReducer 钩子
const [
{
shootCount,
countDown
},
dispatch,
] = React.useReducer(
// 处理状态更新逻辑的函数
shootReducer,
// 初始状态
{
shootCount: 3,
countDown: -1
},
// 惰性初始化
(state) => {
if(operate === "paperwork") {
state.shootCount = 5;
} else {
state.shootCount = 8;
}
}
);
// 接下来,我们就进行上下文的提供了
return (
<ShootContext.Provider value = {{
countDown,
shootCount,
dispatch,
}}>
<ChildComponent />
ShootContext.Provider>
);
}
我们将一些状态和 dispatch
传递给子组件,接下来,我们在子组件中进行对应的操作👇
tsx 代码解读复制代码export interface IChildComponentProps {}
export ChildComponent: React.FC<IChildComponentProps> = (props) => {
// 子组件中消费上下文
const { countdown, dispatch } = React.useContext(ShootContext);
return (
// 直接展示相关的状态
<>
<p>CountDown: { countdown }p>
{/* 这里我们通过 dispatch 来更改 shootCount */}
<button onClick={(dispatch) =>{
if ( // something true happen) {
dispatch({ type: "updateCountdown", countDown: 13 });
}
}}>Change ShootCountbutton>
>
);
}
当然,上面我们只是局限在页面中进行展示使用 dispatch
,我们也可以在组件调用的钩子函数中去使用 dispath
来管理代码。
嗯~ 今天的话题到这里结束,【完】❀
评论记录:
回复评论: