
store
掌管整个应用的状态, 整个应用只能有一个store。通过store.getState() 获取应用某个时间点的快照(状态),通过store.dispatch 分发action.Redux 规定: 一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。
reducer
当store收到action ,就要生成一个新的state, 这个计算过程就是reducer。reducer是一个纯函数,即相同的输入,一定得到相同的输出。
action
用户不能直接修改state, state的变化必须是View 导致的, action 就是View 发出的一个通知,表示action 的名称。
redux 重要API
createStore函数:用来生成store。
1
const store = createStore(reducer, initialState, enhancer)
bindActionCreators:将 action 包装成直接可被调用的函数,用户感知不到dispatch的存在。
1
2const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);
return connect(mapStateToProps, mapDispatchToProps)(Node);combineReducers:一个复杂的应用往往state 比较庞大,导致 Reducer 函数也比较庞大,因此如果能把reducer拆分成一个个独立的子Reducer, 最后再把他们合成一个大的reducer,处理起来就比较方便。而combineReducers就是做这件事的,该函数根据state的key去执行响应的子Reducer,并将结果合并到最终的state对象里。
1
2
3
4
5
6
7
8import { combineReducers } from 'redux';
import { storeReducer } from './store/reducer';
import { reserveReducer } from './reserve/reducer';
export const settingReducer = combineReducers({
store: storeReducer,
reserve: reserveReducer,
});applyMiddleware:applyMiddleware(…middlewares) 引入中间件,比如我们经常使用的用于处理异步action的redux-thunk 中间件。
- compose:是一个返回依次执行参数里面的方法的函数, 其内部是通过Array.prototype.reduceRight 函数实现的,一般redux项目使用多个中间件时会用到。
react-redux API
Provider:
Provider其实是一个React 组件,其原理是通过React组件的context 属性实现store 的传递, 进而拿到整个应用的state。1
2
3
4
5
6
7const App = () => {
return (
<Provider store={store}>
<Comp/>
</Provider>
)
};connect:函数是把 redux 的 dispatch 和 state 映射为 react 组件的 props中,将页面里的组件与应用的状态state真正连接起来。
1 | const mapStateToProps = (state, ownProps) => { |
使用middleWare背景:我们知道redux中数据流是同步的,不支持异步action更新或获取数据,但是在实际项目中异步请求数据绝对是高频出现,并且可以说占据了9成以上的业务场景(初始数据列表、获取商品信息、添加购物车等等),因此redux中间件诞生了
redux-saga
redux-saga 就是用来处理上述副作用(异步任务)的一个中间件。它是一个接收事件,并可能触发新事件的过程管理者,为你的应用管理复杂的流程.
redux-saga 的优点:
(1)声明式 Effects:所有的操作以JavaScript对象的方式被 yield,并被 middleware 执行。使得在 saga 内部测试变得更加容易,可以通过简单地遍历 Generator 并在 yield 后的成功值上面做一个 deepEqual 测试。
(2)高级的异步控制流以及并发管理:可以使用简单的同步方式描述异步流,并通过 fork 实现并发任务。
(3)架构上的优势:将所有的异步流程控制都移入到了 sagas,UI 组件不用执行业务逻辑,只需 dispatch action 就行,增强组件复用性。
redux-thunk
redux-thunk 的主要思想是扩展 action,使得 action 从一个对象变成一个函数。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// redux-thunk example
import {applyMiddleware, createStore} from 'redux';
import axios from 'axios';
import thunk from 'redux-thunk';
const initialState = { fetching: false, fetched: false, users: [], error: null }
const reducer = (state = initialState, action) => {
switch(action.type) {
case 'FETCH_USERS_START': {
return {...state, fetching: true}
break;
}
case 'FETCH_USERS_ERROR': {
return {...state, fetching: false, error: action.payload}
break;
}
case 'RECEIVE_USERS': {
return {...state, fetching: false, fetched: true, users: action.payload}
break;
}
}
return state;
}
const middleware = applyMiddleware(thunk);
// store.dispatch({type: 'FOO'});
// redux-thunk 的作用即是将 action 从一个对象变成一个函数
store.dispatch((dispatch) => {
dispatch({type: 'FETCH_USERS_START'});
// do something async
axios.get('http://rest.learncode.academy/api/wstern/users')
.then((response) => {
dispatch({type: 'RECEIVE_USERS', payload: response.data})
})
.catch((err) => {
dispatch({type: 'FECTH_USERS_ERROR', payload: err})
})
});
redux-thunk 的缺点:
(1)action 虽然扩展了,但因此变得复杂,后期可维护性降低;
(2)thunks 内部测试逻辑比较困难,需要mock所有的触发函数;
(3)协调并发任务比较困难,当自己的 action 调用了别人的 action,别人的 action 发生改动,则需要自己主动修改;
(4)业务逻辑会散布在不同的地方:启动的模块,组件以及thunks内部。