一、环境准备
1.1 安装插件
- 在 React 中使用 Redux,官方要求安装两个插件
Redux Toolkit
和 react-redux
;
Redux Toolkit
:(RTK)
- 官方推荐编写 Redux 逻辑的方式,是一套工具的集合,简化书写方式;
- 简化
store
的 配置方式;
- 内置
immer
支持 可变式状态修改;
- 内置
thunk
更好的 异步创建;
- 安装:
npm install @reduxjs/toolkit
react-redux
:
- 用来链接
Redux
和 React组件
的中间件;

- 安装:
- ✅ 统一安装:
npm i @reduxjs/toolkit react-redux
;
1.2 store目录结构设计

- 通常集中状态管理的部分都会单独创建一个
store
目录;
- 应用通常会有很多个子
store
模块,所以创建一个 modules
目录,在内部编写业务分类的子 store
;
store
中的入口文件 index.js
的作用是组合 modules
中所有的子模块,并导出 store
;
二、创建 并 注入 store 实例
- 基于上篇文章,实现点击按钮,数量count变化;
- counterStore模块:里面写主要的逻辑,在当前案例,主要写的是增和减;
- 整体流程如下图所示:(同步修改)
2.1 创建 store 实例
2.1.1 创建 子store 实例
- 目标文件:
src/store/modules/counterStore.js
;
- 子store:
// 导入创建 store 的方法
import { createSlice } from '@reduxjs/toolkit';
const counterStore = createSlice({
// 必填项
name: 'counter',
// 初始状态数据
initialState: {
count: 0
},
// 修改数据 - 同步方法
reducers: {
// 增方法
increment: (state) => {
state.count++;
},
// 减方法
decrement: (state) => {
state.count--;
}
}
});
// 解构出创建 action 对象的函数(actionCreater)
// 并以 按需导出 的方式 导出 actionCreater
export const { increment, decrement } = counterStore.actions;
// 以默认导出的方式导出 reducer函数
export default counterStore.reducer;
2.1.2 组合子store实例, 创建 根store实例
2.2 为 React 注入 store 实例
recat-redux
负责把 Redux
和 React
链接起来,内置 Provider
组件(该插件的内置组件) 通过 store
参数 把创建好的 store
实例 注入到应用中,链接正式建立;
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
// 导入 根store
import store from './store';
// 导入 react-redux 的内置组件 Provider
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
{/* 使用 Provider内置组件,将 App根组件 包裹起来,使用 store 参数,将 根store实例 传入组件 */}
{/* 配合 路由 使用的时候,需使用 Provider 组件包裹路由的 RouterProvider 组件*/}
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
三、Redux 与 React - 基本使用步骤
3.1 React组件 使用 store 中的数据
- 在 React组件 中使用 store 中的数据,需要用到一个钩子函数
useSelector
:
useSelector
作用:
- 把
store
中的数据 映射到 组件中;
- ❗ 注意:
- 使用样例如下:

3.2 React组件 修改 store中的数据
- 在 redux 中,有且仅有 一种 修改store数据 的 方式,提交action;
- React组件 中 修改 store中的数据 需要借助另外一个 hook函数 -
useDispatch
:
useDispatch
:
- 作用:生成提交
action
对象 的 dispatch
函数;
- 代码展示:
import logo from './logo.svg';
import './App.css';
import { useSelector, useDispatch } from 'react-redux';
// DONE 导入创建action对象的方法
import { decrement, increment } from './store';
function App() {
// DONE 使用 store 中的数据
const { count } = useSelector((state) => state.counter);
// DONE 得到 dispatch 函数
const dispatch = useDispatch();
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<hr />
<div>
{/* DONE 调用 dispatch 函数提交 action */}
{/* dispatch函数需要的参数是 action 对象,action对象是通过 decrement / increment (actionCreate)方法得到的 */}
{/* decrement / increment 方法一定要执行,只有执行了才能得到 action 对象 */}
<button onClick={() => dispatch(decrement())}>-</button>
<button onClick={() => dispatch(increment())}>+</button>
<p>{count}</p>
</div>
</header>
</div>
);
}
export default App;
三、Redux 与 React - 提交action传参
- 在上述案例中,我们虽然使用
dispatch
提交了 action
对象,但是没有传参,现在就来看一下提交action的同时传递参数的情况;
- 本节也是结合小案例去看;
- 需求:
- 组件中有两个按钮,
add to 10
,add to 20
可以直接把 count
值修改到对应的数字,目标 count
值是在组件中传递过去的,需要在 提交action
的时候 传递参数;
- ❗ 实现方法 🎯:
- 在
reducers
的 同步修改方法 中添加 action
对象参数,在 调用actionCreate
的时候 传递参数,参数会被传递到 action
对象 payload
属性 上;
- 注意:
- 如果没有传递参数,
action.payload = undefined
;
- 如果传递了参数,
action.payload = 传递的参数
- 代码展示:

- 目标文件:
src/store/modules/counterStore.js
;
// 导入创建 store 的方法
import { createSlice } from '@reduxjs/toolkit';
const counterStore = createSlice({
name: 'counter',
// 初始状态数据
initialState: {
count: 0
},
// 修改数据 - 同步方法
// 支持直接修改
reducers: {
/** 加法 */
increment: (state, { payload }) => {
state.count += payload || 1;
},
/** 减法 */
decrement: (state) => {
state.count--;
},
/** 增加指定数量 */
addToNum(state, action) {
state.count += action.payload;
}
}
});
// 解构出创建 action 对象的函数(actionCreater)
const { increment, decrement, addToNum } = counterStore.actions;
// 获取 reducer 函数
const counterReducer = counterStore.reducer;
// 以 按需导出 的方式 导出 actionCreater
export { increment, decrement, addToNum };
// 以默认导出的方式导出 reducer函数
export default counterReducer;
- 目标文件:
src/App.js
;
import logo from './logo.svg';
import './App.css';
import { useSelector, useDispatch } from 'react-redux';
// DONE 导入创建action对象的方法
import { decrement, increment, addToNum } from './store';
function App() {
// DONE 使用 store 中的数据
const { count } = useSelector((state) => state.counter);
// DONE 得到 dispatch 函数
const dispatch = useDispatch();
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<hr />
<div>
{/* DONE 调用 dispatch 函数提交 action */}
{/* dispatch函数需要的参数是 action 对象,action对象是通过 decrement / increment (actionCreate)方法得到的 */}
<button onClick={() => dispatch(decrement())}>-</button>
<button onClick={() => dispatch(increment())}>+</button>
<p>{count}</p>
</div>
<hr />
<div>
<p>{count}</p>
<button onClick={() => dispatch(increment(10))}>add to 10</button>
<button onClick={() => dispatch(addToNum(20))}>add to 20</button>
</div>
</header>
</div>
);
}
export default App;
四、Redux 与 React - 异步状态操作
- 之前做的都是同步操作,都是同步修改state,但是实际的开发中,我们还有异步的操作(等到接口获取数据之后进进行操作);
- 还是用小案例的形式来说异步操作状态;
- 需求:
- 请求接口,等接口返回数据之后,将数据使用redux保存起来;
- 使用store中的数据,渲染列表;
- 基本流程:
- 与之前同步修改的流程基本一致,就增加了一个修改的配置;

- 基本步骤:
- 创建
store
的写法保持不变,配置同步修改状态的方法;
- 单独封装一个函数,在函数欸不
return
一个函数,在新函数中:
- 封装异步请求,获取数据;
- 调用同步
actionCreater
传入异步数据生成一个 action
对象,并使用 dispatch
提交;
- 组件中
dispatch
的写法保持不变;
五、持久化Redux数据
- 现存问题:
Redux
存入数据之后,如果 刷新浏览器,数据就会丢失;
- 持久化就是防止数据丢失;
- 不管对token如何赋值,只要刷新了浏览器,
tokenInfo
中的属性值就会恢复为空串;
initialState: {
tokenInfo: {
token: '',
refresh_token: ''
}
}
- 问题原因:
Redux
是 基于浏览器内存 的 存储方式,刷新时 状态恢复为 初始值;
- 解决问题:
- 获取并存储数据:
- 将获取到的数据存入
Redux
+ localStorage.setItem(xxx)
;
- 初始化数据:
localStorage.getItem(xxx) ? localStorage.getItem(xxx) : 初始值
;
- 并不一定是要
localStorage
,铁子们可根据项目要求选择;