内容简介:在使用react的过程中,用redux来管理应用中的状态,使应用流更清晰的同时也会有小小的疑惑,比如reducer在redux中时怎么发挥作用的,为什么只要写好reducer,和dispatch特定action配合,store的状态就会更新了,而react组件又是如何和store的状态产生关系的,为什么随着store状态的更新,react组件会被自动更新,下面就从redux的源码开始来总结下这其中的缘由~redux是继承自flux体系,但它放弃了dispatcher,无需使用 event emitters(
在使用react的过程中,用redux来管理应用中的状态,使应用流更清晰的同时也会有小小的疑惑,比如reducer在redux中时怎么发挥作用的,为什么只要写好reducer,和dispatch特定action配合,store的状态就会更新了,而react组件又是如何和store的状态产生关系的,为什么随着store状态的更新,react组件会被自动更新,下面就从redux的源码开始来总结下这其中的缘由~
redux管理状态的原理
redux是继承自flux体系,但它放弃了dispatcher,无需使用 event emitters(事件发送器)(在dispatcher中特定action逻辑里触发事件,组件里监听事件),而使用纯 reducer来代替,那么reducer是如何被调度的,又是如何影响状态更新的,不妨通过源码的逻辑来了解和加深一下~
从redux源码看action,reducer,和store之间的关系
reducer通常是由我们自己来写,在调用 createStore
函数生成store时来传入这个 reducer
,后续调用 store
的 dispatch
方法来触发 action
时,则 reducer
函数会自动被调用来解析 actin
更新 state
,这一切的核心都在 crateStore
方法中
export default function createStore(reducer, preloadedState, enhancer) { ... let currentReducer = reducer let currentState = preloadedState let currentListeners = [] let nextListeners = currentListeners let isDispatching = false function getState() { ... } function subscribe(listener) { ... } function dispatch(action) { ... } function replaceReducer(nextReducer) { ... } function observable() { ... } return { dispatch, subscribe, getState, replaceReducer, [$$observable]: observable } } 复制代码
可以看到createStore方法返回一个属性集合,我们所调用的redux的相关方法都是定义在createStroe方法内部,最后被通过这个属性集合中暴露出来,如处理action的dispath方法,同currentReducer,currentState是createStore方法中的私有变量,由dispath,subscribe,getState等方法共享,我们设置的reducer,redux的state状态,以及state改变之后应该自动触发哪些函数,这些逻辑都是通过这几个内部变量和函数来实现的,下面先来看一下几个核心方法,由我们直接接触到的dispath开始~
dispacth处理action
function dispatch(action) { ... try { //将flag置为true,表明处于分发逻辑中 isDispatching = true //currentReducer即为函入的reducer函数,这里会自动调用currentReducer函数,并将返回值赋给currentState currentState = currentReducer(currentState, action) } finally { isDispatching = false } //调用监听函数 const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action } 复制代码
可以看到,在dispath中调用reducer方法处理action之后,返回值(新的state)会直接赋值给 currentState
,由此可以推测 currentState
应该就是 getState
要返回的状态
getState返回当前的状态
function getState() { if (isDispatching) { throw new Error( ... ) } return currentState //直接返回currentState内部变量 } 复制代码
subscribe订阅状态
function subscribe(listener) { if (typeof listener !== 'function') { throw new Error(...) } if (isDispatching) { throw new Error( ... ) } let isSubscribed = true ... nextListeners.push(listener) return function unsubscribe() { ... } 复制代码
在subscribe中,传入的listener函数会被添加进nextListeners数组中,当dispatch方法被调用时自动触发,react-redux的状态更新时,UI自动更新的特性是通过subscribe来实现的
通过redux来管理react的状态
首先,设想我们不知道react-redux库来连接react和redux,来试一下单纯的通过redux作为react组件的状态管理器
创建store
//首先,创建一个reducer处理函数 function todoApp(state = initialState, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return ... case ADD_TODO: return ... default: return state } } //创建store const store = createStore( todoApp ); 复制代码
各组件之间共享store的状态
要在各组件之间共享变量store有两种方式可取,一种是通过props共享,一种是通过context实现,其中props共享变量需要每一层组件之间层层传递该变量,这样做无疑很麻烦,尤其是组件之前嵌套层次比较深的时候,所以我们这里用react的context属性来实现共享store
根组件提供context
class App extends Component { getChildContext() { return { store: this.props.store }; } render() { return <ToDoList />; } } App.childContextTypes = { store: React.PropTypes.object } 复制代码
子组件获取context
class VisibleTodoList extends Component { componentDidMount() { const { store } = this.context; this.unsubscribe = store.subscribe(() => this.forceUpdate() ); } render() { const props = this.props; const { store } = this.context; const state = store.getState(); // ... } } VisibleTodoList.contextTypes = { store: React.PropTypes.object } 复制代码
如上所示,在需要获取store状态的组件中,在组件加载完成后需要获取关心得context的变量值store,同时订阅事件,当store的状态变化后触发组件本身的强制更新,而render中只需用 store.getState
获取store的状态值即可
用react-redux来简化组件的写法
上例中写了一个组件的实现还好,但当组件多的时候,每个组件都需写自己的获取context,订阅事件强制更新自身,获取state,这样的样板代码,实际是没必要的,完全可以把这部分抽象出来,而react-redux就帮我们做了这些,让我们省去了自定义context和订阅事件,获取state等操作
省去自定义含有context属性的根组件
要利用 redux
来管理状态,需要在祖先组件的 context
属性中指定 store
,而这一定式化的操作可以有 react-redux
库中的 Provider来完成
,示例如下
<Provider store={store}> <App /> </Provider> 复制代码
省去手动订阅store的状态变化事件
上节中提到过,要实现store的状态更新后能自动更新react组件,则组件需在挂载后调用 store
的 subscribe
方法来订阅 store
中状态的变更,而这块儿样板代码则可以由 react-redux
库中的 connect
创建的容器组件来自动完成
class TodoList extends Component { render(){ ... } } const mapStateToProps = state => { return { todos: getVisibleTodos(state.todos, state.visibilityFilter) } } const mapDispatchToProps = dispatch => { return { onTodoClick: id => { dispatch(toggleTodo(id)) } } } const VisibleTodoList = connect( mapStateToProps, mapDispatchToProps )(TodoList) 复制代码
其中mapStateToProps提供从Redux store state到展示组件的 props的映射 ,mapDispatchToProps接收dispatch方法并提供期望注入到展示组件的 props 中的回调方法。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 深入理解 FilterChainProxy【源码篇】
- 深入理解 WebSecurityConfigurerAdapter【源码篇】
- 深入koa2源码
- 深入理解channel:设计+源码
- 深入浅出Semaphore源码解析
- 深入剖析Vue源码 - 组件基础
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
勇敢新世界‧互聯網罪與罰
許煜、劉細良 / CUP / 2005 / $48
我天天上網數小時,為的是要在節目裡面介紹世界的最新動態,尤其是網絡這個世界本身日新月異的變化。所以我不可能不注意到BT、共享軟件、 Wikipedia、網絡監管等各種影響政治、社會、經濟及文化的重要網絡現象。但是我發現市面上一直沒有一本內容充實全面,資料切時的中文參考書,直到這本《互聯網罪與罰》。而且,最大的驚喜是它易讀好看,簡直就像故事書。 梁文道 鳳凰衛視 《網羅天下......一起来看看 《勇敢新世界‧互聯網罪與罰》 这本书的介绍吧!