转载的~react

redux——入门2

2017-03-30  本文已影响30人  我只是个NPC

redux——入门1里面,我简要介绍了redux的核心概念,并举了一个简单的计数器demo的例子,用于展示在react中怎么使用redux。现在,我打算把这个简单的demo变得复杂一点,引入react-redux和redux中一些其他的概念。

工具分享

在本篇正式开始之前,我想先分享一个用于快速构建react应用的脚手架工具,传送门:https://github.com/facebookincubator/create-react-app

概念引入

我会在这个升级版的demo里面,引入三个东西,Provider(react-redux),combineReducers(redux),connect(react-redux),如果你想更深入的了解react-redux中的各个角色,这里有个很好的解释https://github.com/jasonslyvia/a-cartoon-intro-to-redux-cn

Provider

这是一个组件,没有其他特殊的作用,但是我们需要将它包裹在整个组件树的最外层,只有这样,其内部的子孙组件才能使用connect来绑定store。

connect

这是一个函数,由react-redux提供,其返回依然是一个函数,该函数会处理视图与store绑定的细节,具体的使用方法后面会做介绍。

combineReducers

这也是一个函数。在上一章,我们的reducer是一个单一的函数,在处理类似于计数器这样的简单应用时,我们不会看出有什么问题,但是当整个系统变得复杂后,单一的reducer就会变得臃肿不堪,所以我们需要对reducer进行分片,每一个reducer用于单独处理一部分state,而combineReducers就是将分片的reducer合并为一个整体,这个函数的实现也比较简单。

counter升级版

因为参照了react的官方示例,因此整个例子所使用的语法和上个简化版的例子会有比较大的出入。

入口文件index.js

import React from 'react';
import ReactDOM from 'react-dom';
import {createStore} from 'redux';
import {Provider} from 'react-redux';
import reducer from './reducers';
import Root from './components/root';

let store = createStore(reducer);

ReactDOM.render(
  <Provider store={store}>
    <Root></Root>
  </Provider>,
  document.getElementById('root')
);

同简化版本相比,这里我们引入了Provider,并将其包裹在了组件的最外层。

reducers/index.js

import {combineReducers} from 'redux';
import counter from './counter';

const all = combineReducers({
  count: counter
});

export default all;

在这里,我们调用了combineReducers方法,将counter这个reducer合并到主reducer上,因为计数器这个demo很简单,所以我们只将state划分了一个属性count,而counter这个reducer和简化版的没有什么区别,姑且还是贴一下代码

export default (state=0, action) => {

  switch(action.type) {
    case 'INCREMENT': 
      return state + 1;
    case 'DECREMENT': 
      return state - 1;
    default: 
      return state;
  }
}

前面说过,combineReducer的实现其实是蛮简单的,其实就是返回一个函数,每次处理action的时候,这个函数会遍历所有的reducer来处理这个action,然后将所有结果打包返回,代码和下面类似

// combineReducers
const combineReducers = ( reducers ) => {
    return ( state = {}, action ) => {
        return Object.keys(reducers).reduce(
            ( nextState, key ) => {
                nextState[key] = reducers[key](
                    state[key],
                    action
                );
                return nextState;
            },
            {}
        );
    };
};

components/root.js

这是我们的根组件

import React from 'react';
import InputBox from '../containers/input-box';
import ShowBox from '../containers/show-box';

export default () => {
  return (
    <div>
      <InputBox></InputBox>
      <ShowBox></ShowBox>
    </div>
  );
};

这个没什么可以讲的,主要看接下来的InputBox和ShowBox

containers/input-box

这是一个纯输入组件

import React from 'react';
import {connect} from 'react-redux';

let InputBox = ({onIncrement, onDecrement}) => {

  return (
    <div>
      <button type="button" onClick={onIncrement}>+++</button>
      <button type="button" onClick={onDecrement}>---</button>
    </div>
  );
};

let mapDispatchToProps = (dispatch) => ({
  onIncrement: () => dispatch({type: 'INCREMENT'}),
  onDecrement: () => dispatch({type: 'DECREMENT'})
});

InputBox = connect(undefined, mapDispatchToProps)(InputBox);

export default InputBox;

在这里我们调用了react-redux的connect方法,当然,如果之前完全没接触过connect函数,看这段代码可能会有点头疼,可以先移步这里connect的api文档。我也可以简单介绍下connect的使用方法,它支持四个参数,我这里只介绍前两个,后两个因为我并没怎么用过,所以暂时不讲。
第一个参数是mapStateToProps(state, [ownProps]),用于选择性的将state中的属性注入到组件的props中,我在show-box中使用了这个参数,所以请看后面的代码。
第二个参数是mapDispatchToProps(dispatch, [ownProps]),用于将需要触发dispatch的方法,注入到组建的props中,在上面的input-box中,我使用了这个参数,将onIncrementonDecrement两个用于dispatch的方法注入到了InputBox中。

container/show-box

这是一个纯展示的组件

import React from 'react';
import {connect} from 'react-redux';

let ShowBox = ({count}) => {
  return (
    <div>
      <p>{count}</p>
    </div>
  );
};

let mapStateToProps = (state) => ({
  count: state.count
});

ShowBox = connect(mapStateToProps)(ShowBox);

export default ShowBox;

唯一需要注意的是用了mapStateToProps

总结

虽然是说是升级版,但也只是多引入了几个东西,总体来说还是算简单,只是概念多了,容易让人糊涂,我被绕了一个上午,好在现在总算有点清醒了,所以记下这些东西,方便之后的回顾。

上一篇下一篇

猜你喜欢

热点阅读