使用React-Redux感悟

说来也惭愧,接触Redux一年多了,却没有深入的去研究过,平时只注重使用层面的东西,认为够用即可。计算机行业里面流行这样一句话“欠的总是要还的”,所以之前欠下的账现在就得来还。

开始之前的必须要说明一下,Redux本身和React之间并没有什么关联,它是一个通用Javscript App模块,用做App State的管理。要在React的项目中使用Redux,比较好的方式是借助react-redux这个库来做连接,这里的意思是,并不是没有react-redux,这两个库就不弄一起用了,而是说react-redux提供了一些封装,一种更科学的代码组织方式,让我们更舒服地在React的代码中使用Redux。

之前,我在很多技术文章上看到过关于react-redux的介绍,说“如果你不知道redux这个东西是什么,那你就不需要使用它”。当时并没有觉得这句话有多大问题,可是后来真正开始做项目,接触redux这个东西之后,觉得这句话应该稍微改一下“如果开发的是一个小项目,没有复杂的产品需求,你不知道redux这个东西是什么,那你就不需要使用它”。言外之意就是,正常开发react-native项目是必须要学会的。为什么这么说呢?第一,做APP难免需要使用缓存,我们不可能手动的借助异步存储asyncStory一个个将数据;第二,动态的刷新页面,比如这个页面的数据变化了,同时需要更新其他页面的数据,不可能大量使用的抛通知的方法;等等

谈完了redux的概念、必要性以及使用场景,下面真正的来介绍redux-redux这个东西!

1.Provider
Provider其实作用很简单,就是一个外层容器,使原来整个应用成为Provider的子组件,将从createStore返回的store放入context中,使子集可以获取到store并进行操作;还记的我们在使用的时候都是this.props.dispatch(…);其实仔细想一下dispatch是store里面的方法,那么为什么可以使用this.props来调用呢?很明显得出一个结论,store或者store里面的某些属性被合并到this.props里面。可能,这个地方说这个有点早,不过完全可能证明Provider是将store传递到根节点及其子集。

2.connect
这个东西要花点功夫,详细说一说了。接着上面的红色部分来讲,为什么store里面的东西到这个地方,变成了用this.props来调用?它包在我们的容器组件的外一层,它接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。这个就是connect的功劳了!

这个地方可能理解起来有点吃力,先举个例子。假设有一间很大的封闭的房间,而且房间只有一个口(connect),房间里面养了很多的动物(组件),这个时候,有一只狗饿了,它就发出叫声(action),外面饲养员(reducer)听到之后,就知道原来是狗饿了,就通过那个口向里面抛一点狗粮(state)。扔进去的狗粮,并不会引起动物们的哄抢,因为只有那只狗才认识(也就说state变化的时候,并不是所有的组件都会render)。如果里面有一个动物发出的叫声饲养员根本听不出来是什么动物发出的,也不会去给它找吃的,因为根本不知道它要什么(也就是说,组件发出action的信号,reducer必须能解析才可以,否则没什么意义)。

接下来,就会出现下面几个问题?

(1)React组件如何响应store的变化?
把connect返回的函数叫做Connector,它返回的是内部的一个叫Connect的组件,它在包装原有组件的基础上,还在内部监听了Redux的store的变化,为了让被它包装的组件可以响应store的变化:

(2)为什么connect选择性的merge一些props,而不是直接将整个state传入?
我们connect的是某个Container组件,它并不承载所有App state,然而我们的handler是响应所有state变化的,于是我们需要优化的是:当storeState变化的时候,仅在我们真正依赖那部分state变化时,才重新render相应的React组件,那么什么是我们真正依赖的部分?就是通过mapStateToProps和mapDispatchToProps得到的。

(3)pure优化的是什么?
顾名思义,就是在发现store变化之后,而且也通过connect将数据merge到props中了,但是这个数据有可能跟上一次是一样的,也就是有可能dispatch多次相同数据的action,要不要重新render,目前的处理是render(个人觉的没有必要再次render)。具体优化的方式就是在shouldComponentUpdate中做检查,如果只有在组件自身的props改变,或者mapStateToProps的结果改变,或者是mapDispatchToProps的结果改变时shouldComponentUpdate才会返回true,检查的方式是进行shallowEqual的比较。

最后,再来介绍一下4个重要connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])的方法。

1.mapStateToProps
[mapStateToProps(state, [ownProps]): stateProps] (Function): 如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并。如果你省略了这个参数,你的组件将不会监听 Redux store的变化。如果指定了该回调函数中的第二个参数 ownProps,则该参数的值为传递到组件的 props,而且只要组件接收到新的 props,mapStateToProps 也会被调用。

2.mapDispatchToProps
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): 如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator,而且这个对象会与 Redux store 绑定在一起,其中所定义的方法名将作为属性名,合并到组件的 props 中。如果传递的是一个函数,该函数将接收一个 dispatch 函数,然后由你来决定如何返回一个对象,这个对象通过 dispatch 函数与 action creator 以某种方式绑定在一起(提示:你也许会用到 Redux 的辅助函数 bindActionCreators())。如果你省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中。如果指定了该回调函数中第二个参数 ownProps,该参数的值为传递到组件的 props,而且只要组件接收到新 props,mapDispatchToProps 也会被调用。

3.mergeProps
[mergeProps(stateProps, dispatchProps, ownProps): props] (Function): 如果指定了这个参数,mapStateToProps() 与 mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中。该回调函数返回的对象将作为 props 传递到被包装的组件中。你也许可以用这个回调函数,根据组件的 props 来筛选部分的 state 数据,或者把 props 中的某个特定变量与 action creator 绑定在一起。如果你省略这个参数,默认情况下返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的结果。

4.options
[options] (Object) 如果指定这个参数,可以定制 connector 的行为。
[pure = true] (Boolean): 如果为 true,connector 将执行 shouldComponentUpdate 并且浅对比 mergeProps 的结果,避免不必要的更新,前提是当前组件是一个“纯”组件,它不依赖于任何的输入或 state 而只依赖于 props 和 Redux store 的 state。默认值为 true。
[withRef = false] (Boolean): 如果为 true,connector 会保存一个对被包装组件实例的引用,该引用通过 getWrappedInstance() 方法获得。默认值为 false。

你可能感兴趣的:(react)