Redux 应用程序嵌套状态中的 mapStateToProps() 状态?

Posted

技术标签:

【中文标题】Redux 应用程序嵌套状态中的 mapStateToProps() 状态?【英文标题】:mapStateToProps() in Redux app nesting state within state? 【发布时间】:2017-02-03 09:07:05 【问题描述】:

我在试图弄清楚为什么我在状态中获取和存储的 JSON 数据没有被映射到我的组件 props 时遇到了困难,但在 console.log()ed 从 mapStateToProps() 函数中出现时却出现了。我做错了什么我在这里没有看到吗?

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

查看 state 对象中如何填充 state 属性:

下面是我的组件:

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);

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

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 澄清派发到 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 商店:

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'));

【问题讨论】:

mapStateToProps 应该得到完整的状态作为参数,你到底在问什么? 当我返回 data: state.data 时,数据数组存在。但是当我尝试使用this.props.data 访问组件内的数据时,它会出现未定义。所以它看起来就像在路上的某个地方迷路了。或者我完全误解了 mapStateToProps 在做什么...... 从您的控制台日志中,看起来您在加载数据之前按下了按钮。还有一件事,尝试在地图函数中调用state.state.data,看起来你的状态格式无效。向我们提供您的减速机。 您是如何创建商店的?它应该是:import createStore, applyMiddleware from 'redux';import app from 'reducers/app'; //exported reducer from your exampleconst store = createStore(app, mymiddleware); 你有多个reducer吗?你在打电话给 combineReducers 吗?如果你是...,你的状态会被调低 【参考方案1】:

所以你的mapStateToPropsdata 正在返回一个对象。你可能想要这个:

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

这将使您能够访问 data 减速器中的字段。此外,从示例中不清楚您将如何使用数据,或者其中包含哪些字段。此外,首先,您的 reducer 未将其将使用的字段初始化为 null 或空值,这肯定会导致错误。从initialState 对象开始可能会更好:

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

const app = (state=initialState, action) => 
 /* .... */

【讨论】:

你是对的。你已经从它的外观中得到了一半的答案。我刚刚从@cema-sp 中注意到的是,出于某种原因,有一个状态对象嵌套在另一个状态对象中。所以一切都显示为state.state.datastate.state.error 而不仅仅是state.data。我的减速器出了点问题,但我不确定是什么问题。【参考方案2】:

经过多次审查、调试和询问其他开发人员,简而言之,这就是我面临的问题:reducer 以及如何将其导入主“清单”文件以管理所有其他 reducer。

基本上,由于我在这个项目中只使用了一个reducer,因此不需要清单reducer 文件。见下文:

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

const rootReducer = combineReducers(
  state: Reducer
);

export default rootReducer;

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

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

简而言之...请注意您的减速器是如何导入到您的 createStore 函数中的,以及它是否是唯一正在使用的减速器,或者是否有多个减速器正在通过清单文件运行排序。

干杯。

【讨论】:

combineReducers 将每个 reducer 的状态嵌套在使用的键下(所以在 state 下,对于 Reducer,在上面的代码中)。在你的情况下,你不应该调用 combineReducers,因为你只有一个 reducer。在一个非平凡的应用程序中,您可能会有很多 reducer,每个都在一个描述性键下(例如,不称为“状态”,而是在您的域中的事物之后调用)。【参考方案3】:

我在mapStateToProps 上遇到了类似的问题,在第一次渲染时,它会将初始状态嵌套在具有状态键的对象中。当我使用调度方法更新状态时,它会创建另一个键值对。 (控制台中的以下条目是当我在 mapStateToProps 函数中控制台记录状态时)。

嵌套的初始状态:

我在我的 reducer 函数中发布了它,我正在为我的默认情况返回状态。

const initialState = 
    stateprop1: false,
    user_text: "empty",
    ;

    const reducer1 = (state = initialState, action)             => 
    switch (action.type) 
        case ACTION_TYPES.SUCCESS:
            return 
                ...state,
                stateprop1: true,
            ;
        case ACTION_TYPES.FAILURE:
            return 
                ...state,
                stateprop1: false,
            ;
        case ACTION_TYPES.USER_INPUT:
            return 
                ...state,
                user_text: action.payload,
            ;
        default:
            return 
                state,
            ;
    
;

​如果我在默认情况下传播状态,则不会观察到嵌套行为。

default:
    return 
        ...state,
    ;

所以现在如果我在 mapStateToProps 函数中控制日志状态,我会得到

非嵌套状态:

我希望这会有所帮助。

【讨论】:

以上是关于Redux 应用程序嵌套状态中的 mapStateToProps() 状态?的主要内容,如果未能解决你的问题,请参考以下文章

在redux状态下更新嵌套在另一个数组中的数组属性的问题

Redux reducers——改变深度嵌套状态

创建可重用的 Redux 连接器(具有相同的 mapState 和 mapDispatch) - 存在 TypeScript 问题

将项目添加到 redux-toolkit 中的嵌套数组

React Redux:为啥这个嵌套组件没有从 redux 状态接收道具?

使用 redux-persist 持久化嵌套状态对象