1

说明:阅读本篇文章需要对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整合的简单实现。

参考

Redux 中文文档
Redux 入门教程-阮一峰

载入中...