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

Store / Slice / Reducer

下面,我们来系统的梳理关于 Redux Store / Slice / Reducer 的基本知识点:


一、核心概念概述

1.1 Redux 三大核心元素

  • Store:整个应用的状态容器,单一数据源
  • Reducer:纯函数,定义状态如何更新
  • Slice:Redux Toolkit 引入的概念,整合 reducer 和 actions 的模块化单元

1.2 三者关系

   Action → Reducer → Store↑           ↓└── Slice ←─┘

二、Reducer 深度解析

2.1 Reducer 的本质

Reducer 是纯函数,格式:(state, action) => newState

  • 输入:当前状态 + action 对象
  • 输出:新状态(不可直接修改原状态)
  • 特性:无副作用,相同输入总是返回相同输出

2.2 基本 Reducer 结构

const initialState = { value: 0 };function counterReducer(state = initialState, action) {switch (action.type) {case 'counter/increment':return { ...state, value: state.value + 1 };case 'counter/decrement':return { ...state, value: state.value - 1 };case 'counter/add':return { ...state, value: state.value + action.payload };default:return state;}
}

2.3 Reducer 最佳实践

  1. 不可变性:永远不直接修改 state
  2. 纯函数:无副作用(API 调用、异步操作等)
  3. 默认状态:总是提供 initialState
  4. 默认情况:处理未知 action 时返回原 state

三、Store 深度解析

3.1 Store 的职责

  • 保存整个应用状态
  • 提供 getState() 方法获取当前状态
  • 提供 dispatch(action) 方法更新状态
  • 提供 subscribe(listener) 注册状态变化监听器

3.2 创建 Store

传统方式
import { createStore } from 'redux';const store = createStore(counterReducer);
Redux Toolkit 方式
import { configureStore } from '@reduxjs/toolkit';const store = configureStore({reducer: {counter: counterReducer,users: usersReducer}
});

3.3 Store 方法详解

// 获取当前状态
const currentState = store.getState();// 派发 action
store.dispatch({ type: 'counter/increment' });// 订阅状态变化
const unsubscribe = store.subscribe(() => {console.log('State changed:', store.getState());
});// 取消订阅
unsubscribe();

四、Slice 深度解析 (Redux Toolkit)

4.1 什么是 Slice

Slice 是 Redux Toolkit 的核心概念,包含:

  • 特定功能模块的初始状态
  • 该模块的 reducer 集合
  • 自动生成的 action creators

4.2 创建 Slice

import { createSlice } from '@reduxjs/toolkit';const counterSlice = createSlice({name: 'counter', // action 类型前缀initialState: { value: 0 },reducers: {increment: state => {state.value += 1; // 使用 Immer,允许"突变"写法},decrement: state => {state.value -= 1;},add: (state, action) => {state.value += action.payload;},reset: () => ({ value: 0 }) // 返回全新状态},// 可选:处理其他 slice 的 actionextraReducers: (builder) => {builder.addCase(userSlice.actions.login, (state) => {state.value = 0;})}
});export const { increment, decrement, add, reset } = counterSlice.actions;
export default counterSlice.reducer;

4.3 Slice 的优势

  1. 简化代码:自动生成 action types 和 creators
  2. 安全"突变":内置 Immer 库,简化不可变更新
  3. 模块化:按功能组织代码
  4. TypeScript 友好:自动推导类型

五、完整工作流整合

5.1 配置 Store

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
import userReducer from './userSlice';const store = configureStore({reducer: {counter: counterReducer,user: userReducer},// 可选配置middleware: (getDefaultMiddleware) => getDefaultMiddleware(),devTools: process.env.NODE_ENV !== 'production'
});export default store;

5.2 React 组件中使用

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, add } from './counterSlice';function Counter() {const count = useSelector((state) => state.counter.value);const dispatch = useDispatch();return (<div><span>{count}</span><button onClick={() => dispatch(increment())}>+1</button><button onClick={() => dispatch(add(5))}>+5</button></div>);
}

六、高级模式

6.1 异步操作 (createAsyncThunk)

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';export const fetchUser = createAsyncThunk('user/fetchUser', // action 类型前缀async (userId, thunkAPI) => {try {const response = await fetch(`/api/users/${userId}`);return await response.json();} catch (error) {return thunkAPI.rejectWithValue(error.message);}}
);const userSlice = createSlice({name: 'user',initialState: { data: null, status: 'idle', error: null },reducers: {},extraReducers: (builder) => {builder.addCase(fetchUser.pending, (state) => {state.status = 'loading';}).addCase(fetchUser.fulfilled, (state, action) => {state.status = 'succeeded';state.data = action.payload;}).addCase(fetchUser.rejected, (state, action) => {state.status = 'failed';state.error = action.payload;});}
});

6.2 实体适配器 (createEntityAdapter)

import { createEntityAdapter, createSlice } from '@reduxjs/toolkit';const todosAdapter = createEntityAdapter();const initialState = todosAdapter.getInitialState({status: 'idle',error: null
});const todosSlice = createSlice({name: 'todos',initialState,reducers: {todoAdded: todosAdapter.addOne,todoUpdated: todosAdapter.updateOne,todoRemoved: todosAdapter.removeOne,todoToggled(state, action) {const todoId = action.payload;const todo = state.entities[todoId];todo.completed = !todo.completed;}},extraReducers: {// 异步处理...}
});// 自动生成选择器
export const { selectAll: selectAllTodos, selectById: selectTodoById } =todosAdapter.getSelectors((state) => state.todos);export const { todoAdded, todoUpdated, todoRemoved, todoToggled } = todosSlice.actions;
export default todosSlice.reducer;

七、实践

7.1 文件结构组织

src/├── app/│   └── store.js├── features/│   ├── counter/│   │   ├── counterSlice.js│   │   └── Counter.js│   ├── todos/│   │   ├── todosSlice.js│   │   └── TodoList.js│   └── users/│       ├── userSlice.js│       └── UserProfile.js└── index.js

7.2 性能优化

  1. 记忆化选择器:使用 createSelector
import { createSelector } from '@reduxjs/toolkit';const selectTodos = (state) => state.todos.items;export const selectCompletedTodos = createSelector([selectTodos],(todos) => todos.filter(todo => todo.completed)
);
  1. 组件优化:避免不必要的渲染
// 使用浅比较
import { shallowEqual } from 'react-redux';const user = useSelector(state => state.user, shallowEqual);// 使用 React.memo
const TodoItem = React.memo(({ todo }) => {// ...
});

7.3 测试策略

Reducer 测试:

import counterReducer, { increment, add } from './counterSlice';test('increment action', () => {const previousState = { value: 0 };expect(counterReducer(previousState, increment())).toEqual({ value: 1 });
});test('add action with payload', () => {const previousState = { value: 3 };expect(counterReducer(previousState, add(5))).toEqual({ value: 8 });
});

异步 Thunk 测试:

import { fetchUser } from './userSlice';
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios';test('fetchUser thunk', async () => {const mock = new MockAdapter(axios);mock.onGet('/api/users/1').reply(200, { id: 1, name: 'John' });const dispatch = jest.fn();const state = {};const thunk = fetchUser(1);await thunk(dispatch, () => state, null);const [pending, fulfilled] = dispatch.mock.calls;expect(pending[0].type).toEqual(fetchUser.pending.type);expect(fulfilled[0].type).toEqual(fetchUser.fulfilled.type);expect(fulfilled[0].payload).toEqual({ id: 1, name: 'John' });
});

八、总结

8.1 核心概念总结

概念职责关键特性
Store状态容器单一数据源、dispatch、subscribe
Reducer状态变更纯函数、不可变更新
Slice模块化管理整合 reducer/action、简化代码

8.2 现代 Redux 开发原则

  1. 使用 Redux Toolkit:简化 Redux 逻辑
  2. 遵循 Ducks 模式:将相关逻辑放在同一个 slice
  3. 组件与状态分离:使用容器组件模式
  4. 异步处理标准化:使用 createAsyncThunk
  5. 类型安全:结合 TypeScript
http://www.dtcms.com/a/311722.html

相关文章:

  • 麦肯锡咨询公司PEI经典面试题目汇总
  • Python编程基础与实践:Python循环结构基础
  • 洛谷 P3870 [TJOI2009] 开关-普及+/提高
  • 音视频学习(四十四):音频处理流程
  • 第三章 用户和权限
  • 线程池的实现
  • SQL Server从入门到项目实践(超值版)读书笔记 22
  • 内网穿透系列十:高性能内网穿透工具 rathole,支持Docker一键部署
  • 什么是DOM和BOM?
  • 机器学习-KNN
  • springboot大学生成绩管理系统设计与实现
  • Git 的基本使用指南(1)
  • 人类学家与建筑师:区分UX研究和项目管理的需求分析
  • TFS-2022《A Novel Data-Driven Approach to Autonomous Fuzzy Clustering》
  • LVGL代码框架简介
  • 从底层架构到多元场景:计算机构成与应用的深度剖析
  • Mac电脑安装HomeBrew
  • 从AI智能体出发,重构数据中台:迈向Agentic时代的数据能力体系
  • 微积分基础 | 核心概念 / 公式推导
  • 【51单片机6位数码管密码锁】2022-10-15
  • 入门MicroPython+ESP32:安装逗脑IDE及驱动
  • 深入 Go 底层原理(十一):Go 的反射(Reflection)机制
  • ESP32 外设控制基础:GPIO 应用详解与输入输出案例
  • Text2SQL:如何通过自然语言直接获取数据,打破技术壁垒?
  • ventoy 是一个非常棒的开源工具,可以制作多系统的usb启动盘
  • Allegro降版本工具
  • Python 全局解释器锁
  • 如何静态链接 YARA 库,实现免依赖的独立可执行文件部署
  • MySqL(加餐)
  • 代码随想录Day36:动态规划(最后一块石头的重量 II、目标和、一和零)