Redux 入门教程(二):中间件与异步操作

一个关键问题没有解决:异步操作怎么办?Action 发出后,Reducer 立即算出 State,这叫做同步;Action 发出以后,过一段时间再执行 Reducer,这就是异步。
怎么才能让 Reducer 在异步操作结束后自动执行呢?这就要用到新的工具:中间件(middleware)。

一、中间件的概念
为了理解中间件,让我们站在框架作者的角度思考问题:如果要添加功能,你会在哪个环节添加?
- Reducer:纯函数,只承担计算 State 的功能,不适合承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。
- View:与 State 一一对应,可以看作 State 的视觉层,也不适合承担其他功能。
- Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。
想来想去,只有发送 Action 的这个步骤,即 store.dispatch()
方法,可以添加功能。
二、中间件的用法
1. 基本用法
1 2 3 4 5 6 7 8 9
| import { applyMiddleware, createStore } from 'redux'; import thunk from 'redux-thunk'; import createLogger from 'redux-logger';
const logger = createLogger(); const store = createStore( reducer, applyMiddleware(thunk, logger) );
|
2. 异步操作的基本思路
- 操作开始时,送出一个 Action,触发 State 更新为”正在操作”状态
- 操作结束后,再送出一个 Action,触发 State 更新为”操作结束”状态
三、redux-thunk 中间件
1. 安装
1
| npm install --save redux-thunk
|
2. 使用示例
1 2 3 4 5 6 7 8 9 10 11
| const fetchPosts = postTitle => (dispatch, getState) => { dispatch(requestPosts(postTitle)); return fetch(`/some-api/${postTitle}`) .then(response => response.json()) .then(json => dispatch(receivePosts(postTitle, json))); }; };
store.dispatch(fetchPosts('reactjs'));
|
四、redux-saga 中间件
1. 安装
1
| npm install --save redux-saga
|
2. 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import { createStore, applyMiddleware } from 'redux'; import createSagaMiddleware from 'redux-saga'; import { takeEvery } from 'redux-saga/effects';
function* fetchData(action) { try { const data = yield call(Api.fetchUser, action.payload.userId); yield put({ type: "USER_FETCH_SUCCEEDED", user: data }); } catch (error) { yield put({ type: "USER_FETCH_FAILED", error: error.message }); } }
function* watchFetchData() { yield takeEvery("USER_FETCH_REQUESTED", fetchData); }
const sagaMiddleware = createSagaMiddleware(); const store = createStore( reducer, applyMiddleware(sagaMiddleware) ); sagaMiddleware.run(watchFetchData);
|
五、总结
中间件的作用:
- 在 Action 和 Reducer 之间添加功能
- 处理异步操作
- 添加日志
- 错误处理
选择中间件:
- 简单项目:redux-thunk
- 复杂项目:redux-saga
- 需要日志:redux-logger
最佳实践:
- 保持 Action 的简单性
- 将复杂的异步逻辑放在中间件中
- 使用适当的错误处理机制
- 注意性能优化