1

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
   );
}
6
  • 1
    you have a typo this.state.course is defined but "courses" is not. Commented Sep 26, 2016 at 17:53
  • @JustinHerter sorry it should be this.props.courses.map but still getting the same error Commented Sep 26, 2016 at 18:02
  • ??? props.courses is not an array otherwise .map would be defined. console.log("props: ",props) in your constructor to see whats there. Commented Sep 26, 2016 at 18:10
  • Can you share you store/reducers? The courses which is being read of store is null or undefined because of which you are getting this error. Posting relevant code really would help Commented Sep 26, 2016 at 18:14
  • 1
    BTW you should not be doing state.push(action.user) in the case CREATE_USER. If you do so you are adding the user twice. Commented Sep 26, 2016 at 18:28

4 Answers 4

5

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>
    );
  });
}
Sign up to request clarification or add additional context in comments.

Comments

3

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>

6 Comments

I'm afraid this is incorrect. His combineReducers is fine, users: users is simply the longer version of users. Secondly, courses is an array but you are returning an object in courseReducer.
yeah here i am returning the state object right.. courses is an array in state object so i guess it should be fine.
@HarkiratSaluja now im getting an error as Reducer "courses" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.
have yo u added default to your switch statement?
this.props.courses.length > 1 will still run into the same problem if this.props.courses is undefined. @TRomesh please give my suggestions a try.
|
3

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;

        }
    }

1 Comment

happy to help :) . Can you please accept the answer?
2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.