redux知识点

avatar

  1. store

    掌管整个应用的状态, 整个应用只能有一个store。通过store.getState() 获取应用某个时间点的快照(状态),通过store.dispatch 分发action.Redux 规定: 一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。

  2. reducer

    当store收到action ,就要生成一个新的state, 这个计算过程就是reducer。reducer是一个纯函数,即相同的输入,一定得到相同的输出。

  3. action

    用户不能直接修改state, state的变化必须是View 导致的, action 就是View 发出的一个通知,表示action 的名称。

redux 重要API

  1. createStore函数:用来生成store。

    1
    const store = createStore(reducer, initialState, enhancer)
  2. bindActionCreators:将 action 包装成直接可被调用的函数,用户感知不到dispatch的存在。

    1
    2
    const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);
    return connect(mapStateToProps, mapDispatchToProps)(Node);
  3. combineReducers:一个复杂的应用往往state 比较庞大,导致 Reducer 函数也比较庞大,因此如果能把reducer拆分成一个个独立的子Reducer, 最后再把他们合成一个大的reducer,处理起来就比较方便。而combineReducers就是做这件事的,该函数根据state的key去执行响应的子Reducer,并将结果合并到最终的state对象里。

    1
    2
    3
    4
    5
    6
    7
    8
    import { combineReducers } from 'redux';
    import { storeReducer } from './store/reducer';
    import { reserveReducer } from './reserve/reducer';

    export const settingReducer = combineReducers({
    store: storeReducer,
    reserve: reserveReducer,
    });
  4. applyMiddleware:applyMiddleware(…middlewares) 引入中间件,比如我们经常使用的用于处理异步action的redux-thunk 中间件。

  5. compose:是一个返回依次执行参数里面的方法的函数, 其内部是通过Array.prototype.reduceRight 函数实现的,一般redux项目使用多个中间件时会用到。

    react-redux API

  6. Provider:
    Provider其实是一个React 组件,其原理是通过React组件的context 属性实现store 的传递, 进而拿到整个应用的state。

    1
    2
    3
    4
    5
    6
    7
    const App = () => {
    return (
    <Provider store={store}>
    <Comp/>
    </Provider>
    )
    };
  7. connect:函数是把 redux 的 dispatch 和 state 映射为 react 组件的 props中,将页面里的组件与应用的状态state真正连接起来。

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
const mapStateToProps = (state, ownProps) => {
// state 是 {userList: [{id: 0, name: '王二'}]}
return {
user: _.find(state.userList, {id: ownProps.userId})
}
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
increase: (...args) => dispatch(actions.increase(...args)),
decrease: (...args) => dispatch(actions.decrease(...args))
}
}

class MyComp extends Component {
static PropTypes = {
userId: PropTypes.string.isRequired,
user: PropTypes.object
};
render(){
const {count, increase, decrease} = this.props;
return (<div>
<div>用户名:{this.props.user.name}</div>
<div>计数:{this.props.count}次</div>
<button onClick={increase}>增加</button>
<button onClick={decrease}>减少</button>
</div>)
}
}

const Comp = connect(mapStateToProps, mapDispatchToProps)(MyComp);

使用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内部。