当前位置: 首页 > 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.lryc.cn/news/608396.html

相关文章:

  • 利用DeepSeek将Rust程序的缓冲输出改写为C语言实现提高输出效率
  • Python爬虫实战:研究SimpleCV技术,构建图像获取及处理系统
  • vulnhub-ELECTRICAL靶场攻略
  • 基于OAuth2与JWT的微服务API安全实战经验分享
  • AbstractExecutorService:Java并发核心模板解析
  • Batch Normalization(BN):深度学习中的“训练加速器”与实践指南
  • Vue 详情模块 3
  • 洛谷 P3372 【模板】线段树 1-普及+/提高
  • 星际漫游闪耀2025LEC全球授权展,三大IP与文旅AI打印机共绘国潮宇宙新篇章
  • 【走遍美国精讲笔记】第 1 课:林登大街 46 号
  • 深入 Go 底层原理(一):Slice 的实现剖析
  • 波士顿咨询校招面试轮次及应对策略解析
  • PYTHON从入门到实践-18Django从零开始构建Web应用
  • 二叉搜索树(C++实现)
  • 蓝桥杯----串口
  • [硬件电路-120]:模拟电路 - 信号处理电路 - 在信息系统众多不同的场景,“高速”的含义是不尽相同的。
  • MyBatis与MySQL
  • 驾驶场景玩手机识别:陌讯行为特征融合算法误检率↓76% 实战解析
  • 综合:单臂路由+三层交换技术+telnet配置+DHCP
  • AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年8月2日第154弹
  • 位菜:仪式锚与价值符
  • 先学Python还是c++?
  • Mybatis学习之各种查询功能(五)
  • Web 开发 10
  • stm32F407 实现有感BLDC 六步换相 cubemx配置及源代码(二)
  • sqli-labs:Less-20关卡详细解析
  • 沿街晾晒识别准确率↑32%:陌讯多模态融合算法实战解析
  • Linux网络-------4.传输层协议UDP/TCP-----原理
  • QUdpSocket 详解:从协议基础、通信模式、数据传输特点、应用场景、调用方式到实战应用全面解析
  • kong网关集成Safeline WAF 插件