mapStateToProps()在Redux app嵌套状态下的状态?

问题描述:

我试图弄清楚为什么我正在获取和存储状态的JSON数据没有映射到我的组件道具,但是当 console.log()从 mapStateToProps()函数中编辑。我做错了什么,我没有在这里看到?

I've hit a wall trying to figure out why the JSON data I'm fetching and storing on state isn't being mapped to my component props, yet appears when console.log()ed from within the mapStateToProps() function. Am I doing something wrong that I'm not seeing here?

编辑:显然状态上的属性被映射到组件但是嵌套。从 mapStateToProps()中记录时, data 属性必须通过州进行访问.state.data 。在此之前(请参阅reducer),当记录 action.data 时,数据将按预期显示。没有奇怪的筑巢。
或许 connect 函数有问题?

Apparently the properties on state are being mapped to the component but are nested. The data property, when logged from within mapStateToProps(), has to be accessed via state.state.data. Prior to this (see reducer), when action.data is logged, the data appears as expected. No strange nesting. Perhaps something is wrong with the connect function?

查看如何在其中填充州财产州对象:

See how there is a state property populated within the state object:

下面是我的组件:

class ViewSelector extends Component {
  componentWillMount() {
    this.props.fetchDataAsync('VIEW ALL');
  }

  selectView(event) {
    // this.props.data comes up undefined despite state being mapped
    // to the component props
    console.log('props: ' + this.props.data);
    this.props.filterData(event.target.innerHTML, this.props.data);
  }

  render() {
    return (
      <section>
        <nav>
          <button onClick={this.selectView.bind(this)}>VIEW ALL</button>
          <button onClick={this.selectView.bind(this)}>VIEW LAST WEEK</button>
          <button onClick={this.selectView.bind(this)}>VIEW LAST MONTH</button>
        </nav>
        <Dashboard data={this.props.data}/>
      </section>
    );
  }
}

function mapStateToProps(state) {
  console.log(state);
  // this console.log shows the state with the data property.
  return {
    data: state.data
  };
}

export default connect(mapStateToProps, actions)(ViewSelector);

编辑:这是澄清的减速器:

Here is the reducer for clarification:

import {
  FETCH_DATA,
  FETCH_DATA_SUCCESS,
  FETCH_DATA_FAILURE,
  FILTER_DATA
} from '../actions/types';
import { getLastWeek, getLastMonth } from './reducer_helper';

const initialState = {
  error: '',
  loading: false,
  data: []
};

/* eslint-disable */
const app = (state = initialState, action) => {
  switch(action.type) {
    case FETCH_DATA:
      return { ...state, error: '', loading: true };
    case FETCH_DATA_SUCCESS:
      // console.log(action.data) returns data as expected.
      // no nesting...until it hits the mapStateToProps() function
      return { ...state, error: '', loading: false, data: action.data };
    case FETCH_DATA_FAILURE:
      return { ...state, error: action.error, loading: false };
    case FILTER_DATA:
      let data;
      if (action.view === 'VIEW LAST WEEK') {
        data = getLastWeek(state.data);
      } else if (action.view === 'VIEW LAST MONTH') {
        data = getLastMonth(state.data);
      } else {
        data = state.data;
      }
      return { ...state, error: '', loading: false, data };
  }
  return state;
}

export default app;

行动创造者澄清对减速机的派遣:

Action Creators for clarification on dispatches to Reducer:

export function fetchData() {
  return {
    type: FETCH_DATA
  };
}

export function fetchDataSuccess(data) {
  return {
    type: FETCH_DATA_SUCCESS,
    data: data
  };
}

export function fetchDataFailure(data) {
  return {
    type: FETCH_DATA_FAILURE,
    data
  };
}

export function filterData(view) {
  return {
    type: FILTER_DATA,
    view
  };
}

export function fetchDataAsync() {
  return dispatch => {
    dispatch(fetchData());

    axios.get(DATA_URL)
    .then(res => {
      dispatch(fetchDataSuccess(res.data));
    }).catch(err => {
      dispatch(fetchDataFailure(err));
    });
  };
}

如何呈现整个应用程序& Redux商店:

How the entire app is being rendered & the Redux store:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

import App from './components/app';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <App />
  </Provider>
  , document.querySelector('.container'));


经过多次审核,调试并询问其他开发人员,简而言之,这是我面临的问题:减速器以及如何将其导入主清单文件以管理所有其他减速器。

After much reviewing, debugging and asking other devs, in a nutshell this is the problem I was facing: The reducer and how it was being imported into a main "manifest" file to manage all other reducers.

基本上,因为我在此项目中仅使用一个reducer ,不需要清单reducer文件。见下文:

Basically, since I was only using one reducer in this project, there was no need for a manifest reducer file. See below:

import { combineReducers } from 'redux';
import Reducer from './reducer';

const rootReducer = combineReducers({
  state: Reducer
});

export default rootReducer;

我不知道为什么这是嵌套状态。也许是因为,从理论上讲,我们将处理具有不同目的的多个reducer(如数据缩减器和用户缩减器),并且需要将它们嵌套到我们的状态树中进行管理。

I don't know exactly why this was nesting state. Perhaps because, theoretically, we would be dealing with multiple reducers with different purposes (like a data reducer and a user reducer) and would need to nest those into our state tree to manage.

state = {
  // here is one nested reducer with its own properties
  data: {
    type: // somevalue,
    filtered: true
  },
  // here is another
  user: {
    name: // somename,
    password: // somepassword
  }
};

简而言之......请注意您的减速机如何导入 createStore 函数,如果它是正在使用的 only 减速器,或者是否有多个reducers通过各种清单文件运行。

In short...be mindful of how your reducer is being imported into your createStore function and if it's the only reducer being used or if there's multiple reducers being run through a manifest file of sorts.

干杯。