function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function.')
}
if (isDispatching) {
throw new Error(/* some error msg*/)
}
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
if (isDispatching) {
throw new Error(/* some error msg*/)
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
漫谈Redux & React-Redux 设计精髓
Redux 设计精髓
Redux 是为 Javascript 应用而生的可预估的状态容器,而React-Redux是针对React应用而提供的可预测状态管理机制。
Redux 由三部分组成:action,store,reducer。action顾名思义是你发起的一个操作,然后丢给reducer,reducer接收一个之前的state和action参数,然后返回一个新的 state 给 store(state 只允许在 reducer 中进行改变)。Store是一个容器,state 存储在这个容器中,redux规定Store仅能有唯一一个,而mobx可以有多个Store。
Store
在redux中,Store 管理着应用程序的状态,我们无法直接修改Store,唯一的方法是通过reducer,而唯一可以触发reducer的是通过Store去dispatch一个action(包含状态变更的信息)。因此,要改变数据,我们需要dispatch一个action。所以,redux应用数据的改变为:
Redux使用“Store”将应用程序的整个状态存储在一个地方。因此,所有组件的状态都存储在Store中,并且它们从Store本身接收更新。单状态树使跟踪 随时间的变化以及调试或检查应用程序变得更容易。
reducer
一个reducer是一个纯函数:
(previousState, action) => newState
,用来执行根据指定 action 来更新 state 的逻辑。reducer决定应用数据的改变纯函数即只要参数相同,相同的输入永远会有相同的输出,纯函数不能修改previousState。reducer每次都要返回一个新状态,新状态由旧状态和action决定。类似的:
Store中的数据通过dispatch action,但action只是提供了actionType和payload,并没有决定Store应如何更新。
reducer 接收actionType和payload,然后switch actionType,在相关条件下进行数据整合,最后结合原Store 的state和action对象生成新的state给Store,进行Store的更新
action 类型常量
其实action就是传递的数据(对象的形式),Redux将所有事件抽象为action。当dispatch action后,Store 收到了 Action 必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。
在大型项目中,为了项目规范,一般把action type定义为常量,单独放一个文件。
因此,redux缺点也是显而易见的,为了一个功能,既要写reducer,还要写action,还要单独写一个文件定义action type
源码简单分析
createStore对外暴露了dispatch,subscribe,getState和replaceReducer方法。
store.subscribe
注册的listener,并返回了unsubscribe
方法,用于注销当前listener。当store tree更新后,依次执行数组中的listener:compose调用了reduce方法,将形如fn(arg1)(arg2)(arg3)...的柯里化函数按照顺序执行。
compose(f, g, h)
形如(...args) => f(g(h(...args)))
,将函数h(...args)
得到的结果作为参数传给函数g,以此类推。例如:applyMiddleware接收中间件为参数,并返回一个createStore为参数的函数。中间件会在每次dispatch的时候执行。
applyMiddleware把中间件放在一个chain数组中,通过compose方法,让每个中间件按照顺序依次传入dispatch参数执行,再组合出新的dispatch
React-Redux
React-Redux
提供了两个重要的对象,<Provider store>
和connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
。redux提供一个全局的Store, react 从 store 拿去数据,store 发生变化,react 重新进行渲染。redux与react-redux关系图
Provider
Provider 是在原有的 APP 上面包一层,然后接收 store 作为 props,然后给 connect 用。connect 接收 store 提供的 state 和 action,返回给我们的 react 组件
Provider内的组件要使用state中的数据,需要使用connect方法进行连接:
connect
connect函数是将React组件连接到Redux Store,允许我们将 store 中的数据作为 props 绑定到组件上。用法如下:
配合babel,使用es7 decorator:
decorator是一个对类进行处理的函数,第一个参数就是所要修饰的类。
对于多个reducer,redux也提供了
combineReducers
方法,可以把多个 reducer 合并成一个 root reducer,最后再将该reducer丢给createStore()
。Redux 数据流动
第一步:调用
store.dispatch(action)
如果在React项目中使用react-redux,则通过connect方法,可以将dispatch方法映射到props上。可以通过:
第二步:Redux Store调用rootReducer
redux 收到 action 过后,调用根 reducer 并返回最新的状态数据。
第三步:接收新状态并publish给订阅者
reducer函数负责处理数据,返回新的state(数据),state变化,触发
store.subscribe()
,所有订阅store.subscribe(listener)
的监听器都将被调用;监听器里可以调用 store.getState() 获得当前 state。