文章目录
- [1. Redux前置知识](#1. Redux前置知识)
-
- [1.1 纯函数回顾](#1.1 纯函数回顾)
- [1.2 Redux的三个核心概念](#1.2 Redux的三个核心概念)
- [2. Redux使用](#2. Redux使用)
-
- [2.1 规范化Redux结构](#2.1 规范化Redux结构)
- [2.2 Redux的三大规则](#2.2 Redux的三大规则)
- [2.3 react-redux --- 高阶组件封装库](#2.3 react-redux --- 高阶组件封装库)
- [2.4 异步获取数据](#2.4 异步获取数据)
- [2.5 react代码调试工具](#2.5 react代码调试工具)
- [2.6 Redux模块拆分](#2.6 Redux模块拆分)
- [3. RTK工具包](#3. RTK工具包)
-
- [3.1 redux toolkit](#3.1 redux toolkit)
- [3.2 使用RTK](#3.2 使用RTK)
-
- [3.2.1 创建reducer片段 ---createSlice](#3.2.1 创建reducer片段 ---createSlice)
1. Redux前置知识
1.1 纯函数回顾
- 确定输入,一定会产生确定的输出;
- 函数在执行过程中,不能产生副作用;
判断下面三个函数是否是纯函数
答案:
- 是
- 不是 (依赖外界)
- 不是 (改变外界)
1.2 Redux的三个核心概念
-
store
-
action
-
reducer
❗️
reducer
是一个纯函数,主要人物是将state
和action
结合起来生成一个新的state
返回,这个返回值将替换之前的state
。
修改state
流程:
state.dispatch({type: ... , action: {...})
- 触发reducer ,产生新
state
state
更新
如何知道store数据修改了呢?
答:使用subscribe
javascript
componentDidMount() {
// 订阅store数据
this.unsubscribe = store.subscribe(() => {
console.log('store change:', store.getState());
})
}
componentWillUnmount() {
// 取消订阅
this.unsubscribe()
}
2. Redux使用
2.1 规范化Redux结构
index.js
- 创建store
- 传入reducer
javascript
import { createStore } from 'redux';
// const { createStore } = require('redux'); // createRedux现已弃用
const initialStore = {
name: "Anonymous",
}
const store = createStore(reducer)
export default store;
actionsCreators.js
- 创建actions
javascript
// actions创建
export const changeNameAction = (name) => ({ type: 'change_name', name })
reducer.js
- 单独保存reducer
javascript
import { ADD_NUMBER, CHANGE_NAME } from "./constants";
// reducer 是一个纯函数
// 接收两个参数 state: 之前的状态 action: 描述要产生的改变
export function reducer(state = initialStore, action) {
switch (action.type) {
case CHANGE_NAME:
return { ...state, name: action.name };
case ADD_NUMBER:
return { name }
default:
return state;
}
}
contants.js
- 保存type常量
javascript
// 常量
export const ADD_NUMBER = 'add_number'
export const CHANGE_NAME = 'change_name'
2.2 Redux的三大规则

- 单一数据源
- 整个应用程序的state被存储在一颗
object tree
中,并且这个object tree
只存储在一个store
中: Redux
并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护;- 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改;
- 整个应用程序的state被存储在一颗
- State是只读的
- 唯一修改State的方法一定是
触发action
,不要试图在其他地方通过任何的方式来修改State; - 这样就确保了View或网络请求都不能直接修改state,它们只能通过action来描述自己想要如何修改state;
- 这样可以保证所有的修改都被集中化处理 ,并且按照严格的顺序来执行,所以不需要担心
race condition(竟态)
的问题;
- 唯一修改State的方法一定是
- 使用纯函数来执行修改
- 通过reducer将旧state和actionsl联系在一起,并且返回一个新的State:
- 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分;
- 但是所有的
reducer
都应该是纯函数,不能产生任何的副作用;
2.3 react-redux --- 高阶组件封装库
之前讲到了高阶组件
,在实际开发中我们一般使用封装好的库直接调用,而不是自己封装高阶组件,现在来学习一下react-redux
这个高阶组件库,这个库主要是将react
和redux
联系在一起。

2.4 异步获取数据

从服务器获取数据我们可以选择在组件的componnetDidMount
中发送请求获取,但其实获取数据也是需要在redux
中去完成的。
所以我们选择在传递action
时先获取数据再传递到reducer
,但如果我们是这样写的:
javascript
axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
console.log(res.data);
return { type: CHANGE_BANNERS, banners: [] }
}).catch(err => {
return { type: CHANGE_BANNERS, banners: [] }
})
也就是获取数据后直接返回一个action对象,但其实返回的会是一个Promise对象,不符合redux
的规范(传入一个action
对象或者一个中间件函数)。
中间件我们需要使用到redux-thunk
这个库,首先进行安装:
npm i redux-thunk
javascript
const store = createStore(reducer, applyMiddleware(thunk));
之后就可以创建异步获取数据的action
javascript
// 异步获取数据的action
export const fetchHomeDataAction = () => {
// 使用redux-thunk中间件,返回一个函数(内置dispatch和getState)
return (dispatch, getState) => {
axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
console.log(res.data, res.data.data.banner.list);
dispatch(changeBannersAction(res.data.data.banner.list))
})
}
}
需要注意的是返回的函数中thunk
内置了dispatch
和getState
,这里只需要调用普通的action
修改数据即可。
2.5 react代码调试工具
首先安装这两个工具
- redux-devtools
- react-devtools
默认开发环境开启,生产环境关闭。

2.6 Redux模块拆分

3. RTK工具包
3.1 redux toolkit
- 在前面我们学习Redux的时候应该已经发现,redux的编写逻辑过于的繁琐和麻烦。
- 并且代码通常分拆在多个文件中(虽然也可以放到一个文件管理,但是代码量过多,不利于管理);
- ReduxToolkit包旨在成为编写Redux逻辑的标准方式,从而解决上面提到的问题;
- 在很多地方为了称呼方便,也将之称为"RTK";
npm i @reduxjs/tookit react-redux

3.2 使用RTK
3.2.1 创建reducer片段 ---createSlice
- name: 代替action的type;
- initialState: 初始值;
- reducers: 与之前的一样,但这里需要注意是函数
javascript
import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: 'counter',
initialState: {
counter: 888
},
reducers: {
addNumber(state, action) {
state.counter++
}
}
})
// 导出的是counterSlice.reducer (不是counterSlice.reducers)
export default counterSlice.reducer
index.js
javascript
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from './modules/counter';
const store = configureStore({
reducer: {
counter: counterReducer
}
})
export default store;