说明:阅读本篇文章需要对Redux有一定的了解,对Redux不了解的同学可先看看这篇文章Redux技术架构简介(一)
1. React中引入react-redux
为了让Redux和React更好的配合,Facebook专门开发了一个npm包--react-redux,可以这样引入你的项目: npm install --save react-redux
当然不引用也完全可以(Redux包是必须要引用的),只不过会增加一些开发量,还会带来一些额外的性能开销。
2. 展示组件与容器组件
Redux的React绑定库的基本开发思想是展示组件与容器组件相分离。展示组件只负责页面呈现,不处理数据,不维护状态;容器组件负责页面的运行逻辑,获取展示组件中的消息,处理内部数据,更新状态等。
3. 展示组件的实现
React引入redux后,应用中只有单一的state树,react的每个组件都可以抛弃state的相关逻辑,改为从props获取,包括要执行的一些用户事件行为。
引入redux后的react组件变为:
class MainContent extends React.Component{ constructor(props){ super(props); this.sortResult = this.sortResult.bind(this); this.showSlider = this.showSlider.bind(this); } sortResult(data){ this.props.setPhoto(data); } showSlider(index){ this.props.showSlider(index); } componentDidMount () { this.props.fetchPosts(); } render(){ let {isFetching,isValidate} = this.props; let sliderNode = null; if(this.props.photo.length){ sliderNode = <PhotoSliderContainer data={this.props.photo} />; } return ( <div className="mainContent"> <Header title="photo" /> <SortContainer data={this.props.photo} sortResult={this.sortResult}/> <PhotoItemsContainer data={this.props.photo} showSlider = {this.showSlider}/> {sliderNode} </div> ); } };
可以看到,MainContent组件除了展示外,几乎没有任何的逻辑处理(subscribe和dispatch的逻辑都放到了容器组件),所有的数据都是通过this.props从父组件中获取。
4. 容器组件的实现
容器组件实现了将展示组件和redux关联在一起。技术上讲,容器组件就是使用 store.subscribe() 从 Redux state 树中读取部分数据,并通过 props 来把这些数据提供给要渲染的组件。建议每个展示组件对应一个容器组件,这样可以很清晰的找到映射关系。
mapStateToProps函数
从名字上可以看出,这个函数实现了从state(reducer中定义的)到展示组件props 的映射。示例代码如下:
const mapStateToProps = (state,ownProps) => { return { photo : state.photomainReducer.photoData,video : state.photomainReducer.videoData,isFetching : state.photomainReducer.isFetching,isValidate : state.photomainReducer.isValidate } }
传入的state是应用中唯一的状态树,我们从相应组件的reducer中读取state,分别映射到一个自定义属性中,这样就可以在展示组件中直接调用对应属性(props)了。
mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。
mapDispatchToProps函数
同样我们也可以猜到,这个函数的作用是将期望执行的dispatch方法的返回值映射到展示组件的props上。示例代码如下:
const mapDispatchToProps = (dispatch,ownProps) => { return { slider:(data) => dispatch(photomainAction.showSlider(data)) } }
比如我们想dispatch一个showSlider的action,通过这个方法映射之后,就可以直接这样写:
this.props.slider(data)
即mapDispatchToProps封装了dispatch方法。此外,还可以通过redux提供的bindActionCreators函数进一步封装,上面的代码可以改写如下:
const mapDispatchToProps = (dispatch,ownProps) => { return bindActionCreators({ slider:photomainAction.showSlider },dispatch); }
如果import时的action名和你想定义的属性名一样,甚至还可以简化:
const mapDispatchToProps = (dispatch,ownProps) => { return bindActionCreators({slider},dispatch); }
connect函数
上面2个方法实现了state和action到props的映射,我们还需要把这2个函数连接在一起,并且要关联到一个具体的展示组件,这样就可以在展示组件中使用这种映射关系了。示例代码如下:
const PhotomainContainer = connect( mapStateToProps,mapDispatchToProps )(Photomain);
其中,Photomain是一个展示组件。
每一个容器组件都包含一个对应的展示组件,我们可以把这些容器组件当做一个普通的react组件进行组合,整合的最后一步就是如何把store传入到每个组件中。
5. 传入Store
Store保存了整个应用的单一状态树,所有容器组件都需要从store中读取,我们可以store作为属性传递给每个组件,子组件通过props获取,但是如果嵌套过深,写起来会很麻烦。还好,react-redux提供一个叫provider的组件,他可以让所有组件都可以访问到store(他的实现原理实际上是利用了react的context功能),而不必显示的一层层传递了。
ReactDOM.render( <Provider store={store}> <PhotomainContainer></PhotomainContainer> </Provider>,$(".main-wrap")[0] );
有一点要注意,provider内的组件只能有一个,所以需要将所有组件先封装成一个组件再用provider包裹起来。
6. 总结
Redux的引入使React彻底脱离了对数据状态的管理,可以让React更专注于View的展现,实际上这也是react善于做的事情。单独看react,我们甚至感觉不到redux的存在,使逻辑层和视图层更加清晰(redux负责逻辑,react负责视图),当然一部分原因要归功于react-redux包做了很好的封装。
以上就是React与Redux整合的简单实现。