1 是什么
Redux 是一个可以管理数据的第三方库,能够协助 React 等界面库对数据进行统一管理。
Redux 并不是必须的,当应用中的数据交互比较简单,使用 React 内部的 state、props、context、ref 等可以轻松完成时,就不必使用 Redux 来对数据进行统一管理。
2 设计核心
- 唯一数据源
- 只能通过 Action 触发 Store 的修改
- Reducer 是纯函数
3 中间件
3.1 Middleware
3.1.1 是什么
在 Redux 中,从形式上讲,Middleware 的格式为 ({ getState, dispatch }) => next => action
的函数。
在 Redux 中,从功能上讲,Middleware 是 dispatch 之后、reducer 之前的扩展点。
Middleware 最优秀的特性就是可以被链式组合,在一个项目中可以使用多个独立的第三方 middleware。
3.1.2 有什么作用
在 Redux 中,通过 Middleware 可以扩展 store.dispatch 功能 ,如 可以进行日志记录、创建崩溃报告、调用异步接口或者路由等等。Middleware 最常用的场景就是异步 action。
3.2 redux-thunk
3.2.1 是什么
thunk 是包裹了表达式的函数,通过函数来包裹表达式,进而达到延迟/异步执行表达式的目的。
redux-thunk 是 Redux 中,用来延迟执行 dispatch 的中间件。
3.2.2 有什么作用
redux-thunk 的作用是使 redux 能够异步 dispatch action。
redux-thunk 使 store.dispatch 可以接收函数类型的 actionCreator(dispatch 默认只支持对象类型的 actionCreator),将 strore.dispatch( actionObj ) 包裹在函数类型的 actionCreator 内部,进而达到**异步 dispatch(action) **的目的。
1 | export const getListDataAction = () => { |
3.2.3 使用方法
安装
1
npm install redux-thunk
配置
1
2
3
4
5
6
7
8
9//store/index.js
//基本配置
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
// Note: this API requires redux@>=3.1.0
const store = createStore(rootReducer, applyMiddleware(thunk));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//store/index.js
// 和 redux-devtools 一起使用时的配置
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";
const composeEnhancers =
typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;
const enhancer = composeEnhancers(applyMiddleware(thunk));
const store = createStore(reducer, enhancer);
使用
1
2
3
4
5
6
7
8
9
10
11// createAction.js 文件
// getListDataAction 返回的 action 是个函数
// 这个函数被有一个 dispatch 参数
export const getListDataAction = () => {
return (dispatch) => {
axios.get("/api/list.json").then((response) => {
dispatch(initListAction(response.data));
});
};
};1
2
3
4
5
6
7
8
9
10//dispatch 一个函数后 store 会立即执行此函数
class TodoList extends Component {
//...
componentDidMount() {
//getListDataAction() 返回一个函数
//当 dispatch 接收到一个函数类型的 action 时,会立即执行返回的函数,并传递 dispatch 参数
store.dispatch(getListDataAction());
}
}
3.2.4 源码
1 | // redux-thunk 中间件核心代码实现****************************** |
4 API
4.1 createStore
1 | createStore(reducer, [preloadedState], enhancer) |
- store.subscribe()
- store.dispatch(action)
- store.getState()
1 | //createStore 源码中,有 enhancer 参数时的核心代码实现************************ |
4.2 combineReducers
1 | combineReducers(reducers) |
可以合并多个 reducer
1
2
3
4
5
6
7
8
9
10rootReducer = combineReducers({potato: potatoReducer, tomato: tomatoReducer})
// rootReducer 将返回如下的 state 对象
{
potato: {
// ... potatoes, 和一些其他由 potatoReducer 管理的 state 对象 ...
},
tomato: {
// ... tomatoes, 和一些其他由 tomatoReducer 管理的 state 对象,比如说 sauce 属性 ...
}
}
4.3 applyMiddlleware
1 | applyMiddlleware(...middlewares) |
参数:
- middlewares 是由中间件组成的数组,middleware 之间无需相互关心
- middleware 函数的形式为:({ getState, dispatch }) => next => action
功能描述:
- 创建一个可以扩展 store 的函数
返回值:
- 添加了 middleware 的 store ,返回值形式为: createStore => createStore
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66//applyMiddlleware 源码*********************************
function applyMiddleware() {
//将 middlleware 重新放进数组 middlewares 中
for (var _len = arguments.length, middlewares = new Array(_len), _key = 0; _key < _len; _key++) {
middlewares[_key] = arguments[_key];
}
return function (createStore) {
return function () {
var store = createStore.apply(void 0, arguments);
var _dispatch = function dispatch() {
throw new Error('Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.');
};
var middlewareAPI = {
getState: store.getState,
dispatch: function dispatch() {
return _dispatch.apply(void 0, arguments);
}
};
var chain = middlewares.map(function (middleware) {
/* midddleware 的函数形式:
function (_ref) {
var dispatch = _ref.dispatch,
getState = _ref.getState;
return function (next) {
return function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
};
};
*/
return middleware(middlewareAPI);
});
/*chain 数组中的函数形式:
function (next) {//next 为下一个中间件
return function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
};
*/
/*
执行 compose(f, g, h) 返回值为:
(...args) => f(g(h(...args))
故 _dispatch 为 f(g(h(store.dispatch))
*/
_dispatch = compose.apply(void 0, chain)(store.dispatch);
return _objectSpread2({}, store, {
dispatch: _dispatch
});
};
};
}
//*******************************************************************1
2
3
4
5
6
7
8
9
10//示例
import { createStore, applyMiddleware} from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";
const enhancer = applyMiddleware(thunk);
const store = createStore(reducer, enhancer);
export default store;
4.4 compose
1 | compose( ...functions ) |
参数:
- 多个需要组合的函数,除了最右边的函数,其余函数都只能接收一个参数,每个函数的返回值都会作为相邻左边函数的参数。
返回值:
- 返回从右到左依次执行函数参数的组合函数,如
compose(f, g, h) 会返回 (...args) => f(g(h(...args)))
- 返回从右到左依次执行函数参数的组合函数,如
功能描述:
- 从右到左组合多个函数,使用 compose 来依次执行多个 store enhancer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//redux 中 compose 核心代码实现*********************************
function compose() {
for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) {
funcs[_key] = arguments[_key];
}
//.....
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce(function (a, b) {
return function () {
return a(b.apply(void 0, arguments));
};
});
}
//***************************************************************
4.5 bindActionCreator
1 | bindActionCreator(actionCreators, dispatch) |
参数:
actionCreators:如下两种类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//第一种: 一个 actionsCreator 的函数
initItemAction = (value) => {
return {
type: INIT_ITEM,
value,
};
};
//第二种:由多个 actionCreator 组成的对象
import * as TodoActionCreators from './TodoActionCreators';
console.log(TodoActionCreators);
// {
// addTodo: Function,
// removeTodo: Function
// }dispatch: Store.dispatch
返回值:
- actionCreators
功能描述:
修改 actionCreators 中每个 actionCreator 的实现,将其包裹在 dispatch 中。修改后的效果为,执行 actionCreator 创建 action时 ,会同时执行 dispatch(action),使得执行 actionCreator 的返回值为 dispatch(action) 后的结果。
下面例子对比使用 bindActionCreator 前后写法的变化
1
2
3
4
5
6
7
8
9
10import * as TodoActionCreators from './TodoActionCreators';
//不使用 bindActionCreator 时,创建完 action, 需要手动执行 dispatch
let action = TodoActionCreators.addTodo('Use Redux');
dispatch(action);
//使用 bindActionCreator 把 TodoActionCreators 和 dispatch 绑定后,创建完 action 的同时会在内部自动执行 dispatch
this.boundActionCreators = bindActionCreators(TodoActionCreators, dispatch);
boundActionCreators.addTodo('Use Redux');
1
2
3
4
5
6
7//源码************************************************
function bindActionCreator(actionCreator, dispatch) {
return function () {
return dispatch(actionCreator.apply(this, arguments));
};
}
//源码************************************************