了解React Redux Reducer和MapstateToProps

时间:2019-01-14 00:17:38

标签: reactjs redux

我无法理解redux状态如何基于操作有效负载和reducer函数分配状态对象。以下是我的示例代码。我在不同部分做了笔记并提出了问题,但总的来说,这是我的问题:

  • 为什么下面的选项2不起作用?
  • 为什么我必须使用state.competitions而不是state.items将状态映射到我的CompetitionList道具?
  • 任何资源都可以很好地了解react和redux连接以及映射功能的工作方式。我已经阅读过官方文档并进行了一些谷歌搜索,但是也许有人参考过,他们发现他们更容易理解映射状态和调度的所有不同选项和方式。

我的操作代码:

function getAll() {
    return dispatch => {
        dispatch(request());

        myService.getAll()
            .then(
                competitions => dispatch(success(competitions)),
                error => dispatch(failure(error))
            );
    };

    function request() { return { type: constants.GETALL_REQUEST } }
    function success(competitions) { return {type: constants.GETALL_SUCCESS, competitions}}
    function failure(error) { return {type: constants.GETALL_FAILURE, error}} 
}

我的减速器代码:

import { constants } from '../_constants';

const initialState = {items: [], loading: false, selected: null}

export function competitions(state = initialState, action) {
  switch (action.type) {
    case constants.GETALL_REQUEST:
      return {
        loading: true
      };
    case constants.GETALL_SUCCESS:
          console.log("the action value: ", action)
      return {
        items: action.competitions
      };
    case constants.GETALL_FAILURE:
          console.log("the failed action value: ", action)
      return { 
        error: action.error
      };
    default:
      return state
  }
}

在我的组件中,有一个mapStateToProp函数,该函数传递给我进行连接。第一个不起作用。为什么?

选项1-不起作用

function mapStateToProps(state) {
    const { selected, ...competitions } = state.competitions;

    return {
        competitionList: competitions,
        isLoading: state.loading
    };
}

export default connect(mapStateToProps)(Dashboard);

此方法有效,但我希望CompetitionList变量具有返回的项目数组而不是整个状态对象,因此我尝试执行类似competition: state.competitions.items的操作,但是会引发错误。

选项2-部分起作用(我只想分配比赛项目)

const mapStateToProps = (state) => ({
    competitionList: state.competitions,
    isLoading: state.loading
});


export default connect(mapStateToProps)(Dashboard);

我不能做

const { competitionList } = this.props;

{competitionList.map(competition =>
     <tr key={competition.competitionId}>
        <td>{competition.competitionName}</td>
     </tr>
 )}

我必须做:

const { competitionList } = this.props;

{competitionList.items.map(competition =>
     <tr key={competition.competitionId}>
        <td>{competition.competitionName}</td>
     </tr>
 )}

1 个答案:

答案 0 :(得分:2)

我认为您缺少的一点是当您组合减速器时,每个减速器都会有一个钥匙,因为它们是对象。

在组合减速器的文件中,您可能会有类似的内容:

import { combineReducers } from 'redux'
import todos from './todos'
import competitions from './competitions'

export default combineReducers({
  todos,
  competitions
})

之后,您的状态将如下所示:

{
  todos:{},
  competitions:{
    items: [],
    loading: false,
    selected: null
  }

}

解释说,我认为一切都会变得更容易。

选项1-不起作用:它不起作用,因为您在competitions状态内没有competitions属性。即使有,也不应在其之前使用...。如果您将competitions的{​​{1}}替换为items,因为items处于competitions状态之内:

function mapStateToProps(state) {
    const { selected, items } = state.competitions;

    return {
        competitionList: items,
        isLoading: state.loading
    };
}

export default connect(mapStateToProps)(Dashboard);

或者我们可以改进它,使其更短:

function mapStateToProps(state) {
    const { selected, items } = state.competitions;

    return {
        items,
        selected
        isLoading: state.loading
    };
}

export default connect(mapStateToProps)(Dashboard);

通过这种方式,您可以使用代码的这一部分:

const { items } = this.props;

{items.map(competition =>
   <tr key={competition.competitionId}>
      <td>{competition.competitionName}</td>
   </tr>
 )}

我想指出的另一点是,您的isLoading变量可能也不起作用,因为您正试图直接从状态而不是状态下的reducer读取它。

已编辑:我错过了另一点。减速器总是必须返回整个状态,而不仅仅是它的一个属性。

import { constants } from '../_constants';

const initialState = {items: [], loading: false, selected: null, error: null}

export function competitions(state = initialState, action) {
  switch (action.type) {
case constants.GETALL_REQUEST:
  /*return {
    loading: true
  };*/
  //returning that I will overwrite your competition state with this object.
  

  // this will keep all the competition state and will gerenate a new object changing only the loading attribute
  return {
    ...state,
    loading:true
}
case constants.GETALL_SUCCESS:
      console.log("the action value: ", action)
  return {
    ...state,
    items: action.competitions
  };
case constants.GETALL_FAILURE:
      console.log("the failed action value: ", action)
  return { 
    ...state,
    error: action.error
  };
default:
  return state
  }
}