当前位置: 首页 > java >正文

React状态管理Context API + useReducer

在 React 中,Context API + useReducer 是一种轻量级的状态管理方案,适合中小型应用或需要跨组件共享复杂状态的场景。它避免了 Redux 的繁琐配置,同时提供了清晰的状态更新逻辑。


1. 基本使用步骤

(1) 定义 Reducer

类似于 Redux 的 reducer,用于处理状态更新逻辑:

// reducer.js
export const initialState = {count: 0,user: null,
};export function reducer(state, action) {switch (action.type) {case 'INCREMENT':return { ...state, count: state.count + 1 };case 'DECREMENT':return { ...state, count: state.count - 1 };case 'SET_USER':return { ...state, user: action.payload };default:return state;}
}

(2) 创建 Context 和 Provider

使用 createContext 创建 Context,并用 useReducer 管理状态:

// AppContext.js
import { createContext, useReducer } from 'react';
import { initialState, reducer } from './reducer';// 1. 创建 Context
export const AppContext = createContext();// 2. 创建 Provider 组件
export function AppProvider({ children }) {const [state, dispatch] = useReducer(reducer, initialState);return (<AppContext.Provider value={{ state, dispatch }}>{children}</AppContext.Provider>);
}

(3) 在顶层组件包裹 Provider

// App.js
import { AppProvider } from './AppContext';
import Counter from './Counter';function App() {return (<AppProvider><Counter /></AppProvider>);
}

(4) 在子组件使用状态

通过 useContext 获取 statedispatch

// Counter.js
import { useContext } from 'react';
import { AppContext } from './AppContext';export function Counter() {const { state, dispatch } = useContext(AppContext);return (<div><p>Count: {state.count}</p><button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button><button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button></div>);
}

(5) 数据持久化

Context + useReducer 管理的状态是纯内存状态,当页面刷新时,这些数据会丢失,因为 JavaScript 的内存会被清空,恢复到初始状态。
在 React 的 Context + useReducer 架构中实现数据持久化(页面刷新不丢失),可以通过以下方案实现:


手动 localStorage 存储
实现步骤
  1. 初始化时读取 localStorage
  2. 每次更新状态时同步存储
import { createContext, useContext, useReducer, useEffect } from 'react';// 1. 创建 Context
const AppContext = createContext();// 2. 定义 Reducer
function reducer(state, action) {switch (action.type) {case 'INCREMENT':return { ...state, count: state.count + 1 };case 'SET_USER':return { ...state, user: action.payload };default:return state;}
}// 3. 持久化 Provider
function AppProvider({ children }) {const [state, dispatch] = useReducer(reducer,JSON.parse(localStorage.getItem('appState')) || { count: 0, user: null });useEffect(() => {localStorage.setItem('appState', JSON.stringify(state));}, [state]);return (<AppContext.Provider value={{ state, dispatch }}>{children}</AppContext.Provider>);
}
优点
  • 代码简洁,适合小型应用。
  • 无需第三方库。
缺点
  • localStorage 是同步操作,可能阻塞主线程。
  • 存储大小有限(通常 5MB)。
注意事项
  • localStorage 只能存字符串,复杂数据需用 JSON.stringify

2. 进阶优化

(1) 封装自定义 Hook

避免在每个组件里重复写 useContext

// hooks/useAppContext.js
import { useContext } from 'react';
import { AppContext } from '../AppContext';export function useAppContext() {return useContext(AppContext);
}

然后在组件中使用:

const { state, dispatch } = useAppContext();

(2) 优化性能(避免不必要的渲染)

默认情况下,Context 的更新会导致所有消费者组件重新渲染。可以使用 memo + 拆分 Context 优化:

// 拆分多个 Context
const CountContext = createContext();
const UserContext = createContext();// 在 Provider 里分别提供
<CountContext.Provider value={{ countState, countDispatch }}><UserContext.Provider value={{ userState, userDispatch }}>{children}</UserContext.Provider>
</CountContext.Provider>

(3) 结合异步操作

可以在 dispatch 里处理异步逻辑(如 API 请求):

async function fetchUser(dispatch) {try {const user = await fetch('/api/user').then(res => res.json());dispatch({ type: 'SET_USER', payload: user });} catch (error) {dispatch({ type: 'SET_ERROR', payload: error.message });}
}// 在组件中调用
fetchUser(dispatch);

3. 优缺点对比

优点缺点
无需额外库,React 原生支持大型应用可能性能较差(需手动优化)
比 Redux 更轻量异步处理较麻烦(需手动封装)
适合中小型应用调试不如 Redux 方便(无 DevTools)

4. 适用场景

  • 小型/中型应用:不想引入 Redux 或 Zustand 时。
  • 组件层级较深:需要跨多层传递状态时。
  • 简单全局状态:如主题、用户登录信息等。

总结

  • Context + useReducer 是 React 内置的状态管理方案,适合轻量级需求。
  • 对于更复杂的状态管理,可考虑 ZustandRedux Toolkit
  • 如果涉及大量异步逻辑,建议结合 React QuerySWR 使用。
http://www.xdnf.cn/news/12267.html

相关文章:

  • Flyway
  • vue3+js示例
  • delphi7 链表 使用方法
  • 基于STM32单片机的电子秤系统设计(原理图+PCB+程序+仿真+文章)
  • SpringCloud——OpenFeign
  • web第十次课后作业--Mybatis的增删改查
  • 微服务架构——配置管理与配置中心
  • 【Java】RxJava解析
  • 麒麟信安系统下修改系统默认记录日志大小
  • 上传、下载功能 巧实现
  • 如何修改项目在浏览器中的小图标
  • 【MATLAB去噪算法】基于CEEMDAN联合小波阈值去噪算法(第四期)
  • 轨道交通可视化,赋能智慧车站运维
  • C++034(一维数组)
  • 基于WSL搭建Ubnutu 20.04.6 LTS(二)-部署Docker环境
  • LoRA:大模型高效微调的低秩之道——原理解析与技术实现
  • 检测到 #include 错误。请更新 includePath。已为此翻译单元(D:\软件\vscode\test.c)禁用波形曲线
  • 力扣面试150题--被围绕的区域
  • std__map,std__unordered_map,protobuf__map之间的性能比较
  • 网页显示:嗯…无法访问此页面,的解决办法和原理
  • 大模型学习
  • 家政维修平台实战14登录验证
  • 如何用 SD-WAN 打破 ERP 内网限制,实现随时随地高效访问?
  • 总结HTML中的文本标签
  • 危化工厂部署人员定位系统的重要性
  • 算法性能分析
  • 智慧赋能:移动充电桩的能源供给革命与便捷服务升级
  • TripGenie:畅游济南旅行规划助手:个人工作纪实(九)
  • Linux 下生成动态库时 -fPIC的作用详解
  • 一些常用的JavaScript简写技巧