react-redux数据流向总结

前言

今天总结的问题是之前自己再segmentfault上自问自答的一道题目。还是放到BLOG里方便自己日后来看。

Q

最近在学习redux,关于action,store,reducer感觉理解起来并不困难。。。
但是结合react,使用react-redux中的一些API进行组件的props与aciton和store的连接时就各种不理解了。。。
首先react-redux中有容器组件和展示组件这两个概念。
我的展示组件如下:component/app.js

class AppComponent extends React.Component {

  render() {
  const { value, increment, decrement } = this.props;
  return (
     <div>
      {value}<button onClick={increment}>加</button>
      <button onClick={decrement}>减</button>
  </div>
    );
   }
}

AppComponent.propTypes = {
  value: PropTypes.number.isRequired,
  increment: PropTypes.func.isRequired,
  decrement: PropTypes.func.isRequired
};

export default AppComponent;

就是一个数字,加,减。然后我的 reducer/counter.js

import {INCREMENT, DECREMENT} from '../actions/const';
const initialState = {
  number: 0
};
function reducer(state = initialState, action) {
    switch (action.type) {
    case INCREMENT: {
      return state.number + 1;
    }
    case DECREMENT: {
      return state.number - 1;
    }
    default: {
      return state;
    }
  }
}
module.exports = reducer;

我的初始state是{number:0}最后是关键的container,也就是容器组件:container/app.js

import React, { Component, PropTypes } from 'react';
import { increment, decrement } from '../actions/';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Main from '../components/App';

class App extends Component {
  render() {
    const {actions, counter} = this.props;
    return <Main actions={actions} counter={counter}/>;
  }
}

App.propTypes = {
  actions: PropTypes.object.isRequired,
  counter: PropTypes.object.isRequired
};

function mapStateToProps(state) {
  const props = { value: state.counter.number };
  return props;
}
function mapDispatchToProps(dispatch) {
  const actions = {increment,decrement};
  const actionMap = { actions: bindActionCreators(actions, dispatch) };
  return actionMap;
}
export default connect(mapStateToProps, mapDispatchToProps)(App);

这里有几个问题:
1:首先,报错:展示组件内的props均报错
Failed prop type: Required prop (value,increment,decrement这三个props) was not specified in AppComponent.(说明我的3个props没有与action和store内的state联系?)

2:我是按照官方的todoMVC的代码写的容器组件。其中为什么要单独加一个 Class app? 其中return

的action和counter如何理解?是从哪里传过来的?

3: mapStateToProps中state.counter的counter是哪里来的?(我看的许多例子。。这个state.后面跟的貌似都是reducer的文件名。) 然后,我的value为什么没有取到reducer内的number:0 呢?

4:最后,mapDispatchToProps函数内,并没有显示的看到我组件内的increment和我的action:increment(decrement同理) 建立联系,那么action和props是如何连接的呢?

A

1:第一个问题。为什么会报错。是因为我根本没有将组建内的三个props传递下来。

class App extends Component {
  render() {
  const {actions, counter} = this.props;
  return <Main actions={actions} counter={counter}/>;
   }
}

其中的actions和counter是从store中传递过来的actions和counter。这里需要这样写:

<Main
  value={counter.number}
  increment={actions.increment}
  decrement={actions.decrement}
/>

需要将组建内的props传递下来,并传递state和action给他们。我们在这里就显示的建立了连接了!
2:为什么要加一个Class app?actuions和counter哪里来的?
我做的这个例子只有一个组件。所以其实不需要这样写。
但是如果,container内需要添加多个组件的时候,我们就需要将组件集中起来,将所有的组件合并。
至于,actions和counter哪里来的。上面也提到了。是通过connect传递过来的!
mapStateToProps和mapDispatchToProps一个把store中的state传递了过来,一个把绑定好的actions传递了过来
3,4:上面其实也已经提到了。

function mapStateToProps(state) {
  const props = { counter: state.counter };
  return props;
}

它将store内counter这个reducer内的state传递给了counter,再传递给了我们的组件。

function mapDispatchToProps(dispatch) {
  const actions = {increment,decrement};
  const actionMap = { actions: bindActionCreators(actions, dispatch) };
  return actionMap;
}

它将所有的actions绑定到了store上,然后组件可以通过actions.传递action给我们的组件最后。这几处改完后,我发现我的reducer也写错了。。我的state是一个对象,必须返回一个新的对象。否则reducer就不是纯函数了

 function reducer(state = initialState, action) {
  const nextStateIn = { number: state.number + 1 };
  const nextStateDe = { number: state.number - 1 };

  switch (action.type) {
    case INCREMENT: {
      return nextStateIn;
    }
   case DECREMENT: {
      return nextStateDe;
    }
    default: {
      return state;
    }
  }
}

结语

上次的结尾预告是关于flex的,那么刚好,之前的公司发来的我没做好的复试题目是有关于响应式开发那么我结合flex布局,再下一篇总结一下吧!over。