TRomesh
TRomesh

Reputation: 4481

Errors while Using map functions in React

Im trying to display some data using map function but im keep on getting warnings and errors. they are

Warning: There is an internal error in the React performance measurement code. Did not expect componentDidMount timer to start while render timer is still in progress for another instance.

and the other one is

Uncaught TypeError: Cannot read property 'map' of undefined

i found out that this.props.courses.map returns null but i still cant figure out why?

import React,{PropTypes} from 'react';
import {connect} from 'react-redux';
import * as courseActions from '../actions/courseActions';


class CoursesPage extends React.Component{

    constructor(props,context){
       super(props,context);

       this.state={
         course:[{id:1,title:'hello'}]
       };

       this.onTitleChange = this.onTitleChange.bind(this);
       this.onClickSave = this.onClickSave.bind(this);

    }

    onTitleChange(event){
      const course = this.state.course;
      course.title = event.target.value;
      this.setState({course:course});
    }

    onClickSave(){
       this.props.dispatch(courseActions.createCourse(this.state.course));
    }

    courseRow(){
      return this.props.courses.map((course)=>{
          return(
            <div key={course.id}>{course.title}</div>
          );
      });
    }

    render(){
      return(
        <div>
          <h2>hello</h2>
          <h3>{this.courseRow()}</h3>
          <input type="text" onChange={this.onTitleChange} value={this.state.course.title}/>
          <input type="submit" value="save" onClick={this.onClickSave}/>
        </div>
      );
    }

}

CoursesPage.propTypes ={
   dispatch: PropTypes.func.isRequired,
   courses: PropTypes.array.isRequired
};

function mapStateToProps(state,ownProps){
     return{
        courses:state.courses
     };
}

export default connect(mapStateToProps)(CoursesPage);

here is my reducer

export default function courseReducer(state = [],action){
    switch(action.type){
       case 'CREATE_USER':
         state.push(action.user);
          return [...state,Object.assign({},action.user)];
         default:
          return state;
      }
}

my rootReducer

import {combineReducers} from 'redux';
import users from './userReducer';
import courses from './courseReducer';

const rootReducer = combineReducers({
  users:users,
  courses:courses
});

export default rootReducer;

the store

import {createStore,applyMiddleware} from 'redux';
import rootReducer from '../reducers/rootReducer';

export default function configureStore(initialState){
  return createStore(
     rootReducer,
     initialState
   );
}

Upvotes: 1

Views: 5555

Answers (4)

TRomesh
TRomesh

Reputation: 4481

After modifying the code with the help of both @Harkirat Saluja and @Yang Shun. i manages to fix the issue which was initializing courses so i changed my Reducer as below

state = [] did the trick!

 export default function courseReducer(state = [],action){
        switch (action.type) {
          case 'CREATE_COURSE':
                return [...state,Object.assign({},action.course)];
           default:
            return state;

        }
    }

Upvotes: 3

Harkirat Saluja
Harkirat Saluja

Reputation: 8114

In your reducer where are you updating courses?? I can only see users from the code you posted.

 const initialState = {
        courses : [],
 }



export default function courseReducer(state =initialState,action){
    switch(action.type){
       //create a course or update it , else value is 
       //undefined and your map would throw error.
       case 'CREATE_COURSES':
         return Object.assign({},state,{
                 courses : action.user}
          );
         default:
          return state;
      }
}

Also in your render method you need to check if this value is filled then only run map.

 <h3>{this.props.courses.length > 1 ? this.courseRow() : null}</h3>

Upvotes: 3

Yangshun Tay
Yangshun Tay

Reputation: 53169

Your Redux store's courses might be undefined at the start and hence this.props.courses becomes undefined. Trying to access .map of undefined will give you the error you mentioned above. There are a few ways to fix this:

Approach 1 (Recommended): Set the initial value of the state.courses to empty array [] in your the reducer. Refer to the documentation on Reducers to see how to set an initial state: http://redux.js.org/docs/basics/Reducers.html.

Approach 2: Set a default value for props.courses in mapStateToProps.

function mapStateToProps(state,ownProps){
  return {
    courses: state.courses || []
  };
}

Approach 3: Check that this.props.courses is not undefined or null before rendering it:

courseRow() {
  if (!this.props.courses) {
    return null;
  }

  return this.props.courses.map((course)=>{
    return(
      <div key={course.id}>{course.title}</div>
    );
  });
}

Upvotes: 5

Tom Goldenberg
Tom Goldenberg

Reputation: 566

Your mapStateToProps is returning a reducer instead of actual props that you can use right away. It should probably look like this:

function mapStateToProps(state,ownProps){
     return{
        ...state.courses
     };
}

Upvotes: 2

Related Questions