浅谈React和Redux的连接react-redux
之前一直在探索react相关的东西,手上有个spa项目,于是准备上redux试试水。redux本身和react并没有之间的关联,它是一个通用javscript app模块,用做app state的管理。要在react的项目中使用redux,比较好的方式是借助react-redux这个库来做连接,这里的意思是,并不是没有react-redux,这两个库就不弄一起用了,而是说react-redux提供了一些封装,一种更科学的代码组织方式,让我们更舒服地在react的代码中使用redux。
之前仅通过redux文档来了解react-redux,在一段时间的实践后准备翻一翻源代码,顺便做些相关的总结。我看的代码的npm版本为v4.0.0,也就是说使用的react版本是0.14.x。
react-redux提供两个关键模块:provider和connect。
provider
provider这个模块是作为整个app的容器,在你原有的app container的基础上再包上一层,它的工作很简单,就是接受redux的store作为props,并将其声明为context的属性之一,子组件可以在声明了contexttypes之后可以方便的通过this.context.store访问到store。不过我们的组件通常不需要这么做,将store放在context里,是为了给下面的connect用的。
这个是provider的使用示例:
// config app root const history = createhistory() const root = ( <provider store={store} key="provider"> <router history={history} routes={routes} /> </provider> ) // render reactdom.render( root, document.getelementbyid('root') )
connect
这个模块是算是真正意义上连接了redux和react,正好它的名字也叫connect。
先考虑redux是怎么运作的:首先store中维护了一个state,我们dispatch一个action,接下来reducer根据这个action更新state。
映射到我们的react应用中,store中维护的state就是我们的app state,一个react组件作为view层,做两件事:render和响应用户操作。于是connect就是将store中的必要数据作为props传递给react组件来render,并包装action creator用于在响应用户操作时dispatch一个action。
好了,详细看看connect这个模块做了什么。先从它的使用来说,它的api如下:
connect([mapstatetoprops], [mapdispatchtoprops], [mergeprops], [options])
mapstatetoprops是一个函数,返回值表示的是需要merge进props的state。默认值为() => ({}),即什么都不传。
(state, props) => ({ }) // 通常会省略第二个参数
mapdispatchtoprops是可以是一个函数,返回值表示的是需要merge仅props的actioncreators,这里的actioncreator应该是已经被包装了dispatch了的,推荐使用redux的bindactioncreators函数。
(dispatch, props) => ({ // 通常会省略第二个参数 ...bindactioncreators({ ...resourceactions }, dispatch) })
更方便的是可以直接接受一个对象,此时connect函数内部会将其转变为函数,这个函数和上面那个例子是一模一样的。
mergeprops用于自定义merge流程,下面这个是默认流程,parentprops值的就是组件自身的props,可以发现如果组件的props上出现同名,会被覆盖。
(stateprops, dispatchprops, parentprops) => ({ ...parentprops, ...stateprops, ...dispatchprops })
options共有两个开关:pure代表是否打开优化,详细内容下面会提,默认为true,withref用来给包装在里面的组件一个ref,可以通过getwrappedinstance方法来获取这个ref,默认为false。
connect返回一个函数,它接受一个react组件的构造函数作为连接对象,最终返回连接好的组件构造函数。
然后几个问题:
- react组件如何响应store的变化?
- 为什么connect选择性的merge一些props,而不是直接将整个state传入?
- pure优化的是什么?
我们把connect返回的函数叫做connector,它返回的是内部的一个叫connect的组件,它在包装原有组件的基础上,还在内部监听了redux的store的变化,为了让被它包装的组件可以响应store的变化:
trysubscribe() { if (shouldsubscribe && !this.unsubscribe) { this.unsubscribe = this.store.subscribe(::this.handlechange) this.handlechange() } } handlechange () { this.setstate({ storestate: this.store.getstate() }) }
但是通常,我们connect的是某个container组件,它并不承载所有app state,然而我们的handler是响应所有state变化的,于是我们需要优化的是:当storestate变化的时候,仅在我们真正依赖那部分state变化时,才重新render相应的react组件,那么什么是我们真正依赖的部分?就是通过mapstatetoprops和mapdispatchtoprops得到的。
具体优化的方式就是在shouldcomponentupdate中做检查,如果只有在组件自身的props改变,或者mapstatetoprops的结果改变,或者是mapdispatchtoprops的结果改变时shouldcomponentupdate才会返回true,检查的方式是进行shallowequal的比较。
所以对于某个reducer来说:
export default (state = {}, action) => { return { ...state } // 返回的是一个新的对象,可能会使组件rerender // return state // 可能不会使得组件rerender }
另外在connect的时候,要谨慎map真正需要的state或者actioncreators到props中,以避免不必要的性能损失。
最后,根据connect的api我们发现可以使用es7 decorator功能来配合react es6的写法:
@connect( state => ({ user: state.user, resource: state.resource }), dispatch => ({ ...bindactioncreators({ loadresource: resourceactions.load }, dispatch) }) ) export default class main extends component { }
ok,以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
详解react、redux、react-redux之间的关系
-
浅谈redux以及react-redux简单实现
-
详解关于react-redux中的connect用法介绍及原理解析
-
浅谈react-router HashRouter和BrowserRouter的使用
-
React-Redux的使用详解
-
前端笔记之React(六)ES6的Set和Map&immutable和Ramda和lodash&redux-thunk
-
原生实现一个react-redux的代码示例
-
用react-redux实现react组件之间数据共享的方法
-
react-redux 的使用
-
react-redux中connect的装饰器用法@connect详解