react 3 - redux
前言
“如果你不知道是否需要 Redux, 那就是不需要它. “
虽然有这样一句话, 可是作为开发, 却是必须要学会使用的, 只有你会了以后, 才可以来探讨你的项目里面是否需要Redux.
Flux
react为我们的整个应用提供了界面搭建的方法, 如果你的组件够多, 那么就可以像拼积木一样一点点搭建你的应用. 而react的Render是一个纯函数, 只要组件有同样的state和props, 那么你就会得到同样的view. 而Flux的理念就是使state变成不可写, 而是由action分发的方式在内部处理好数据, 再传给state, 而避免组件自己随意修改state造成不可预知的问题.
Redux
Redux是Flux思想的一种实现方式, 与react结合使用更加方便. 而Redux的设计思想很简单, 就两句话:
- 应用是一个状态机, 视图与状态是一一对应的.
 - 所有的状态, 保存在一个对象里面.
 
基本概念
store
在整个应用中, 只有一个store, 它保存着所有数据. 如果想得到某个时间点的数据, 就需要对store生成快照, 生成快照的方法是store.getState(), 那么这个快照自然就叫做state了. 注意, 此state和组件里面的state不是一个概念, 也不会有直接的交集. Redux规定, 一个state对应一个view, 只要state是相同的, 那么生成的view应该也是一样的.
action
state已经有了数据, 那么自然就需要有改变数据的方式, 这个方式就是action, 同时也是唯一的方式. 对于view, 不能直接接触到state和store, 只能通过发送action的方式来改变store. action是一个对象, 其中type属性是必须的, 其他属性都属于携带的信息, 一般通过payload来传递.
1  | const action = {  | 
action creator
action既然是一个对象, 那么创建这个对象肯定不会是手写, 而是有一个方法来自动生成, 那么生成这个action的方法即action creator.
1  | static addTodo(v) {  | 
addTodo函数即为ADD_TODO的action creator.
dispatch
有了action creator和生成的action, 那么怎么让store知道这个action呢, store.dispatch(action)就是用来发出action的唯一方法.
reducer
声明和使用
当调用store.dispatch之后, 怎么去改变state呢, 这就是reducer的功能了. 每个reducer都是一个函数, 它的参数是当前state和action, 返回值是一个新的state, 这样view就会根据新的state去绘制界面了.
1  | const defaultState = 0;  | 
当创建好reducer函数之后, 需要让store知道这个函数, 然后store会在调用dispatch时, 自动触发所有的reducer函数. createStore中的reducer参数就是让store去连接指定的reducer方法.
纯函数
reducer必须是一个纯函数, 意义是每次执行会得到相同的结果. 所以不能调用Data.now()或Math.random()等方法. 但是由于是纯函数, 基于函数式编程的理念, 是不能改变原始对象的. 所以如果是对象, 返回值应该是return { ...state, ...newState }. 如果对象结构层级特别深, 那么创建newState就会是一个很麻烦的事情, 而且可能会不小心改变state后也会出现其他错误, 这就是为什么需要immutable的原因.
subscribe
store提供subscribe方法来设置一个监听函数, 只要state发生改变, 那么就会执行这个监听函数. subscribe方法返回一个解除监听的函数unsubscribe, 执行unsubscribe就可以取消监听.
1  | let unsubscribe = store.subscribe(() => console.log(store.getState()));  | 
工具函数
combineReducers
一般都会用到的函数, 如果你的reducer有很多个, 那么你就需要用到这个函数创建出一个rootReducers对象来提供给store连接reducer函数.
1  | const RootReducer = combineReducers({  | 
connect
connect方法可以为你的展示组件创建对应的容器组件. connect方法签名为connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]).
mapStateToProps(state, ownProps) : statePropsmapDispatchToProps(dispatch, ownProps): dispatchPropsmergeProps(stateProps, dispatchProps, ownProps): propsoptions为选项, 使用到的地方很少
mapStateToProps(state, ownProps) : stateProps
从名字可以看出, 此函数是把state的属性赋给props(此处state非组件state, 而是store的state). 当state变化, 或者ownProps变化的时候, mapStateToProps都会被调用(此处ownProps是上级组件的props传入到connect生成的高阶组件的props, 不是被connect的组件的ownProps), 计算出一个新的props更新给组件, 并触发组件的componentWillReceiveProps方法.
1  | const mapStateToProps = (state, ownProps) => {  | 
mapDispatchToProps(dispatch, ownProps): dispatchProps
从名字也可以看出来, 是把dispatch方法映射到props上, 不过没有mapStateToProps那么直观. 在ownProps变化时, mapDispatchToProps 也会再次执行, 计算出一个新的值更新到props上.
1  | const mapDispatchToProps = (dispatch, ownProps) => {  | 
传入这个函数以后, 在组件的props上, 就可以使用addTodo方法了.redux提供了bindActionCreators用来快速将action生成可调用的函数.
1  | const mapDispatchToProps = (dispatch, ownProps) => {  | 
mergeProps(stateProps, dispatchProps, ownProps): props
这个函数就是用来将上面两个函数生成的值复制到props里面的函数, 如果不传这个函数, 默认调用的是Object.assign方法.
createStore
createStore(reducer, initialState, enhancer): store是创建store的唯一方法, reducer即全部的reducers, initialState为store的初始化值, enhancer即可以让我们生成加强版本的store的方法.
1  | //createStore中enhancer有关的源码  | 
可以看到enhancer应该是一个方法, 接收createStore作为参数, 返回一个新createStore的方法, 再传入reducer, preloadedState参数执行.
applyMiddleware
applyMiddleware方法生成的函数即enhancer所表示的值, 从enhancer实现可以看出, applyMiddleware有两种调用方式.
1  | //1  | 
ReduxThunk
重点说说ReduxThunk中间件, 它是与后台交互的必备中间件, 使我们在dispatch中可以发出异步的action. 它的源码也是十分简单.
1  | function createThunkMiddleware(extraArgument) {  | 
使用的时候也很简单.
1  | static addTodo(v) {  | 
Provider
Provider严格来说应该是组件, 不过class本质也是function, 所以放在一起了. Provider组件即让整个应用都可以直接拿到store的组件. 原理是react中的context.
1  | //源码  | 
react 3 - redux

