美文网首页
react-redux(一)

react-redux(一)

作者: 珍珠林 | 来源:发表于2017-05-26 23:46 被阅读0次

    Redux着眼于对状态整理的维护,而不会产生出具体变动的部分。React是一个由状态整体输出界面的view层实现,因此二者可以说是绝配。

    如何在React项目中使用Redux


    当我们在说如何使用Redux时,说的其实是如何获取并使用store内容(状态数据),以及创建并触发action的过程。

    一. 获取并使用store


    • 属性传递store状态数据
      Redux的特点是整个应用的状态信息保存在一个store中,因而需要由store将数据从React组件树节点传入。为了在数据变化时更新界面,还需要对store进行监听:
    function render() {
        const state = store.getState();
        React.render(
          <App state={state}/>,
          document.getElementById('app')
        );
    }
    
    store.subscribe(render);
    render();
    

    这样,在组件App中,可以通过this.props.state获取状态信息。组件App可以进一步将状态信息以props的形式传递给其子孙节点:

    class App extends React.Component {
        render() {
            return (
              <Header content={this.props.title}/>
            );
        }
    }
    

    正如例子中的组件Header,每个组件都可以从上层节点获取它所需的信息。
    然而,当项目规模变大,组件层级变多时,情况会急剧恶化,因为如果某个组件处在组件数第n级,那么没修改一个属性或增加一个组件,都需要改动n-1处,这是无法想象的维护成本。
    下面是很自然思考到的解决这个问题的办法

    • 组件自行获取store状态数据

    对应的的做法是,把createStore的结果通过一个独立的模块以module export的方式暴露出来,所有组件都可以直接去import这个模块得到store,然后对store进行subscribe:

    // store.js
    import reducers from 'reducers';
    export default createStore(reducers);
    
    // TodoFilter.js
    import store from 'store';
    export default class TodoFilter extends React.Component {
        constructor() {
            super();
            this.state = {
                filter: null
            };
        }
        componentDidMount() {
            store.subscribe(() => {
                this.setState({
                    filter: store.getState().filter
                });
            });
        }
        render() {
            // 界面渲染
        }
    }
    

    在组件挂载完成后监听store的变化,取出最新状态数据,并通过组件自身的setState方法更新组件的state信息,自动触发重新渲染组件界面。
    通过这种方式,我们顺利地解决了前面遇到的问题,但依然存在一些问题:

    1. 组件私自与store建立联系,致数据流难以追溯。
    2. 拥有内部state的组件不便于测试。
    3. 每个需要访问store组件都实现一份subscript&setState这样的逻辑略显繁琐。

    react-redux将是上面这些问题较为成熟的、通用的解决方案。

    二. 创建与触发action


    在Flux架构中,store的状态改变必须由action引起,除了获取与使用store状态数据外,另外一个与store打交道的方式便是创建与触发action。在Redux中,这个过程包含两个部分:

    1. 创建action,使用actionCreator
    2. 触发action,通过store.dispatch将action作用到特定的store上

    不难发现,触发action的方法dispatch,也面临着一样的问题,就是获取store。下面介绍针对这一问题的官方答案:react-redux。

    react-redux


    react-redux是Redux官方提供的React绑定,用于辅助在React项目中使用Redux,性能优异且灵活强大。API相当简单,包括一个Provider组件和一个connect高阶方法。

    • Provider

    Provider是store提供者。只要把组件树根节点包裹在Provider中,整个组件树上的节点都可以通过connect获取store:

    ReactDOM.render(
      <Provider store={store}>
        <MyRootComponent />
      </Provider>
    );
    
    • connect

    connect是用来“连接”store与组件的方法,用法如下:

    import { add } from 'actions';
    
    function mapStateToProps(state) {
        return {
            num: state.num
        };
    }
    
    function mapDispatchToProps(dispatch) {
        return {
            onBtnClick() {
                dispatch(add()); // add()为action creator
            }
        };
    }
    
    function Counter(props) {
        return (
          <p>
            {props.num}
            <button onClick={props.onBtnClick}>+1</button>
          </p>
        );
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Counter);
    

    在这个示例中,我们通过connect让组件Counter得以连接store,从store中取得num信息并在按钮单击时触发store上的add方法。

    • enhancer

    connect()的执行结果是一个“高阶组件”,我们称之为enhancer。
    高阶组件指符合以下条件的函数:接收一个已有的组件作为参数,返回一个新组件,后者将前者封装于内部。一般使用高阶组件都是为了对已有组件进行某些能力上的增强。
    这里enhancer对传入组件进行怎样的增强呢?答案便是接触store的能力。
    原有组件Counter不直接与store打交道,甚至不知道store与Redux的存在,而经过enhancer处理得到的组件,即上例中最终被export的内容,能够直接接触到store,监听、读取状态数据并触发action。这里的store,就是先前通过Provider引入的。

    react-redux通过React在0.1.4版引入的context特性实现了store内容的隐式传递:Provider作为整个组件树的根节点,通过实现getChildContext方法将store提供给它的的子孙们,而enhancer通过组件的context属性获取store对象,从而可以调用其提供的subscript、getState、dispatch等方法。

    相关文章

      网友评论

          本文标题:react-redux(一)

          本文链接:https://www.haomeiwen.com/subject/mumaxxtx.html