简介

JS 应用的状态容器,提供可预测的状态管理

三大原则

1、单一数据源

整个应用的全局 state 被存储在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中

2、state是只读的

唯一改变 state 的方法就是触发 action, action 是一个用于描述已发生事件的普通对象。

3、使用纯函数来执行修改

为了描述 action 如何改变 state tree,你需要编写纯的 reducers。

单向数据流
1
view -> dispath(action) -> reducer -> subscribe -> view(流回)

流程

同步

同步的 redux 可以非常清晰的体现出 3 大原则和单向数据流。

异步

redux 本身不提供处理异步的方式,如果你需要异步的操作需求,可以添加 middleware 来增强 redux 的功能。

核心

顶级API

1、createStore(reducer, [preloadedState], [enhancer])

创建store接收三个参数:

  • reducer 是一个函数,返回新的状态,接受两个参数:当前的 state 和要触发的 action ;
  • preloadedState 为初始时的 state 对象;
  • enhancer 可选使用。用第三方第能力如中间件、时间旅行、持久化来增强 store;

2、combineReducers(reducers)

合并 reducer 单元,返回combination(state, action),即 reducer。

3、applyMiddleware(…middlewares)

扩展中间件

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
import compose from './compose'

/**
* @param {...Function} middlewares The middleware chain to be applied.
* @returns {Function} A store enhancer applying the middleware.
*/
export default function applyMiddleware(...middlewares) {
return (createStore) => (...args) => {
const store = createStore(...args)
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
// 暴露getState和dispatch给第三方中间件
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args),
}
// 获取中间件数组传入参数
const chain = middlewares.map((middleware) => middleware(middlewareAPI))
// 组合成新的dispatch
dispatch = compose(...chain)(store.dispatch)
// 返回新的store
return {
...store,
dispatch,
}
}
}

4、 bindActionCreators(actionCreators, dispatch)

包装

5、compose(…functions)

组合函数

1
2
3
4
5
6
7
8
9
10
11
export default function compose(...funcs) {
if (funcs.length === 0) {
return (arg) => arg
}

if (funcs.length === 1) {
return funcs[0]
}

return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
Store API
  • getState
  • dispath
  • subscribe
  • replaceReducer

当 enhancer 传参的时候

1
2
3
4
5
6
7
8
9
10
11
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error(
`Expected the enhancer to be a function. Instead, received: '${kindOf(
enhancer
)}'`
)
}
// 返回增强后的createStore
return enhancer(createStore)(reducer, preloadedState)
}
getState

返回应用当前的 state 树

1
2
3
function getState() {
return currentState
}
dispath

分发 action。这是触发 state 变化的惟一途径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function dispatch(action) {
...
try {
isDispatching = true
// 使用currentReducer处理传入的currentState, action
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
//通知所有之前通过subscribe订阅state更新的回调listener
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}

return action
}
subscribe

添加一个变化监听器。每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function subscribe(listener) {
...
// 确保只有第一次执行unsubscribe()才是有效的,只取消注册当前listener
var isSubscribed = true

ensureCanMutateNextListeners()
nextListeners.push(listener)
// 返回取消订阅函数
return function unsubscribe() {
if (!isSubscribed) {
return
}

isSubscribed = false

ensureCanMutateNextListeners()
var index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
replaceReducer

替换 store 当前用来计算 state 的 reducer。

1
2
3
4
5
6
7
8
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}

currentReducer = nextReducer
dispatch({ type: ActionTypes.INIT })
}

扩展

我们知道将 reducer 设计为纯函数,让它们更容易调试和比较;但这也带来了其它问题,比如涉及到接口调用之类的就不能处理。那么中间件便是用来增强 redux 功能的一种中间函数。

以 Redux-thunk 为例,以下为 thunk 的实现源码

1
2
3
4
5
6
7
8
9
10
11
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => // 中间件函数
next => // 中间件函数创建的改造函数
action => { // 改造函数改造后的 dispatch
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}

return next(action);
};
}

生态库

  • Redux Toolkit
  • Redux-thunk
  • React-redux
  • React-redux-router

参考

Redux 中文官网