React学习笔记03:Redux入门

02.redux概念

图书馆模型:

  • React Components:借书的用户
  • Action Creators:借书说的话(借哪本书)
  • Store:图书管理员
  • Reducers(减速器,还原剂 ):记录本

03.使用AntDesign

示例:./03.AntDesign-TodoList
https://ant.design/docs/react/introduce-cn

04.Redux的创建与使用

文件结构

1
2
3
4
5
6
7
8
src
├── index.js
├── TodoList.js
├── store
| ├── index.js
| ├── reducer.js
| ├── actionCreator.js
└── └── actionTypes.js

安装Redux

yarn add redux

创建Reducer和Store

在这一步中我们创建一个Reducer去生成一个存放数据的位置,再把Reducer交给Store。

1
2
3
4
5
6
7
// .store/index.js
import { createStore } from 'redux'
import reducer from './reducer'

const store = createStore(reducer);

export store;
1
2
3
4
5
6
7
8
9
// ./store/reducer.js
const defaultState ={
// 在此初始化rudecuer中的数据
}

export default (state = defaultState, action) => {
return state;
// state 存放数据(存放图书馆里所有书的信息)
}

在组件中使用Redux中保存的数据

  1. 在组件中导入store文件的位置
    1
    import store from '../04.Redux/store.js';
  2. 在组件中可以使用store.getState()获取数据
    1
    2
    3
    4
    5
    // 将store中的数据绑定在state上
    constructor(props){
    super(props);
    this.state = store.getState()
    }

05.Action和Reducer的编写

使用Redux DevTools

在创建store的文件下,添加一句代码

1
2
3
4
const store = createStore(
reducer,
+ window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

组件中直接请求更改数据

1.组件发送修改请求action

在组件中可以直接创建一个action来请求更改Store中的数据,但是这个action必须符合规范,之后组件可以通过调用store.dispatch(action)方法,把action传递给Store

拿TodoList项目来说,当用户在文本框内输入了文字,会触发onChange而调用handleInputChange方法,此时在方法中要向Store中发送一个修改请求,如下:

1
2
3
4
5
6
7
handleInputChange(e) {
const action = {
type: 'change_input_value',
value: e.target.value
}
store.dispatch(action)
}

2.Store转发请求给Reducer

Store接受到一个action后,会将 当前的数据(previousState)操作指令(action) 转发给Reducer(这就是在reducer.js中,要接收的两个变量),这一步是自动执行的。

3.Reducers处理数据

Reducers接收到当前的数据(previousState)和操作的指令(action)后,会将它们对并且处理数据,之后将新的数据(newState)传回给Store。

如在TodoList示例中,在Reducers中设置一个change_input_value的判断方法,去设置数据的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ./store/reducer.js

export default (state = defaultState, action) => {
// state:store上一次存储的数据,action指的是用户传入的那句话
console.log(state, action);

// 查看用户的指令是什么
if (action.type === 'change_input_value') {
// 对previousState进行一次深拷贝
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}

return state;
}

在此要注意的是:reducer可以接收state,但是绝对不能修改state,必须对state进行深拷贝后再处理数据。

4.Store拿到Reducer的处理结果

Store拿到Reducer的处理结果后,会将旧的数据替换为新的数据,这个阶段Store并未将数据交给组件,需要组件去自我感知数据发生了变化并自行更新界面。

5.组件感知Store中数据变化

在组件中的constror中调用store.subscribe()设置一个事件订阅,它的参数为个方法函数,用来检查store中的数据(state)是否发生了变化,如果发生了变化,就会调用参数中传入的方法,从而更新组件state中的数据,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
constructor() {
... ...
// 注意this绑定(在设置订阅前绑定this)
this.handleStoreChange = this.handleStoreChange.bind(this)
// 订阅store的改变
store.subscribe(this.handleStoreChange)
... ...
}

... ...

handleStoreChange() {
// 组件感知到store数据变化后更新数据
this.setState(store.getState());
}

06.ActionType的拆分

./store目录下创建actionTypes来存放action的命名

1
2
3
4
// actionTypes.js
export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_ITEM = 'add_todo_item';
export const DELETE_TODO_ITEM = 'delete_todo_item';

之后将actionTypes.js中的变量分别导入TodoList.jsruducer.js中,之后在定义action时,调用变量即可

1
2
// reducer.js
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './actionTypes'

07.使用ActionCreator统一创建action

我们按照 组件中直接请求更改数据 的方法直接在业务逻辑中创建action会导致代码变得混乱,为了统一,我们将创建action的方法写入./store/actionCreator文件下,结合actionTypes统一创建action,然后再在业务逻辑中调用。

1
2
3
4
5
6
7
// actionCreator.js
import { CHANGE_INPUT_VALUE } from './actionTypes'

export const getInputChangeAction = (value) => ({
type: CHANGE_INPUT_VALUE,
value
})
1
2
3
4
5
6
7
8
9
// Todolist.js
import { getInputChangeAction } from './store/actionCreator'

... ...

handleInputChange(e) {
const action = getInputChangeAction(e.target.value);
store.dispatch(action)
}

09. 知识点补充

总流程

  1. actionTypes.js 中创建变量存放action的操作类型,并向外暴露出变量名,提供给 actionCreator.jsreducer.js 调用。
  2. actionCreator.js 中集中编写生成action对象,设置action对象的类型以及传入的数据名称,向外暴露该对象,供组件在业务逻辑代码部分调取使用。
  3. reducer.js 判断某个action的type,编写与之对应的数据操作,并返回给store。
  4. 在组件业务逻辑代码中调用 actionCreator.js 提供的方法,生成一个action,并利用 store.dispatch() 向store发送一个action。
1
2
3
4
5
文件依赖关系:

actionTypes.js ──[actionType]── actionCreator.js ──[actionObj]── component.js
|
└────[actionType]── reducer.js

注意事项

  1. store是唯一的
  2. 只有store才能变更自己的内容
  3. Reducer必须是纯函数:纯函数指的是,给定固定的输入,就一定会有固定的输出,而且不会有任何副作用

核心API

createStore: 创建store

store.dispatch: 派发action

store.getState: 获取store中的数据内容

store.subscribe: 订阅stote中的改变