react js mapStateToProps triggers Uncaught TypeErr

2020-04-16 03:59发布

I have an index.js which renders all tables in the database.

_renderAllTables() {
const { fetching } = this.props;

let content = false;

if(!fetching) {
  content = (
    <div className="tables-wrapper">
      {::this._renderTables(this.props.allTables)}
    </div>
    );
}

return (
  <section>
    <header className="view-header">
      <h3>All Tables</h3>
    </header>
    {content}
  </section>
);
}

_renderTables(tables) {

return tables.map((table) => {
  return <Table
            key={table.id}
            dispatch={this.props.dispatch}
            {...table} />;               
});
}

render() {
return (
  <div className="view-container tables index">
    {::this._renderAllTables()}
  </div>
  );
 }
}
const mapStateToProps = (state) => (
  state.tables);

export default connect(mapStateToProps)(HomeIndexView);

I changed mapStateToProps from above code to below code.

 const mapStateToProps = (state) => ({
tables: state.tables,
currentOrder: state.currentOrder,
});

The reason why I changed code is that I want to use one of state of currentOrder. I have a state which shows whether table is busy or not. So in order to use that I added currentOrder in mapStateToProps. However, it triggers Uncaught TypeError: Cannot read property 'map' of undefined..

How can I use states from other components? any suggestions for that??

Thanks in advance..

--reducer.js

 const initialState = {
  allTables: [],
  showForm: false,
  fetching: true,
  formErrors: null,
   };


  export default function reducer(state = initialState, action = {}) {
   switch(action.type){
    case Constants.TABLES_FETCHING:
        return {...state, fetching: true};

    case Constants.TABLES_RECEIVED:
        return {...state, allTables: action.allTables, fetching: false};

    case Constants.TABLES_SHOW_FORM:
        return {...state, showForm: action.show};

    case Constants.TALBES_RESET:
        return initialState;

    case Constants.ORDERS_CREATE_ERROR:
        return { ...state, formErrors: action.errors };


    default:
        return state;
   }
 }

标签: reactjs redux
2条回答
贪生不怕死
2楼-- · 2020-04-16 04:05

Your problem is that before fetching successfully tables, your component is rendered with state.tables is undefined.

First of all, best practice is to use selectors rather than json path like state.tables, to be in a separate selectors.js file using reselect lib as follow:

import { createSelector } from 'reselect';

const tablesSelector = state => state.tables;

export default {
  tablesSelector,
}

Second, you need to add reducer for, let's assume, FETCH_ALL_TABLES action using combineReducers from redux lib and most important to initialize tables array with [] before the action is dispatched so as to be defined as follow:

import {combineReducers} from 'redux';

function tables(state = [], {type, payload}) {
  switch (type) {
    case 'FETCH_ALL_TABLES':
      return [
        ...state,
        ...payload,
      ]
  }

  return state;
}


export default combineReducers({
  tables,
});

and in your index.js, may be want update it to:

import selector from './selector';

...

function mapStateToProps(state) {
  return {
    tables: selector.tablesSelector(state),
  }
}
查看更多
Luminary・发光体
3楼-- · 2020-04-16 04:23

You should always check if variable you want to map is defined.

_renderTables(tables) {
    if (tables) {
        return tables.map((table) => {
            return <Table
                key={table.id}
                dispatch={this.props.dispatch}
                {...table} />;               
        });
    }
}
查看更多
登录 后发表回答