5

Im new to React and Redux and still kinda confused a little bit.

My goal is to render a bunch of json datas in the HTML by using GET request. I'm using react and redux to manage the state of the objects, but I believe my problem is that the data is not even there

so basically whenever someone request a URL /courses , he/she will see bunch of data in json.

I get the error in the component

TypeError: Cannot read property 'map' of undefined

Here's the code

Action

export function getCourses() {
  return (dispatch) => {

    return fetch('/courses', {
      method: 'get',
      headers: { 'Content-Type', 'application/json' },
    }).then((response) => {
      if (response.ok) {
        return response.json().then((json) => {
          dispatch({
            type: 'GET_COURSES',
            courses: json.courses
          });
        })
      }
    });
  }
}

Reducer

export default function course(state={}, action) {

  switch (action.type) {
    case 'GET_COURSES':
      return Object.assign({}, state, {
        courses: action.courses
      })
    default:
      return state;
  }


}

Component

import React from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';


class Course extends React.Component {



  allCourses() {
    return this.props.courses.map((course) => {
      return(
        <li>{ course.name }</li>
      );

    });
  }

  render() {
    return (
      <div>
        <ul>
          { this.allCourses() }
        </ul>

      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    courses: state.courses
  }
}

export default connect(mapStateToProps)(Course);

Index reducer, where i combine everything

import { combineReducers } from 'redux';
import course from './course';

export default combineReducers({
  course,
});

Configure Store , where i store the intial state and the reducer

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

export default function configureStore(initialState) {
  const store = createStore(
    rootReducer,
    initialState,
    compose(
      applyMiddleware(thunk),
      typeof window == 'object' && typeof window.devToolsExtension !== 'undefined' ? window.devToolsExtension() : f => f
    )
  );

  return store;
}

I believe why the data is not there is because i didn't call the action? any help would be appreciated.

1
  • Is that your only reducer? Or are you combining reducers somewhere else? Can you show us where you initialise the store? Commented Jul 31, 2016 at 6:14

2 Answers 2

7

mapStateToProps takes the root state as an argument (your index reducer, which is also the root reducer), not your course reducer. As far as I can tell this is the structure of your store:

-index <- This is the root reducer
  -course

So to get the courses from that state, in your component:

// state is the state of the root reducer
const mapStateToProps = (state) => {
  return {
    courses: state.course.courses
  }
}

Also, you might consider initialising the state of the course reducer with an empty array of courses, so if you have to render the component before the action is fired, you won't get the error.

const initialState = {
    courses: []
};

export default function course(state= initialState, action) {

    ...

}

Finally, you're not firing the action at all, so you will never actually get the courses, I assume you want them to be retrieved once the Course component is loaded, for that you can use the componentDidMount event in your component.

First of all, you need to map the action to a property of the component

// Make sure you import the action
import { getCourses } from './pathToAction';

...

const mapDispatchToProps = (dispatch) => {
  return {
    onGetCourses: () => dispatch(getCourses())
  };
}

// Connect also with the dispatcher
export default connect(masStateToProps, mapDispatchToProps)(Course);

Now call the onGetCourses property when the component mounts

class Course extends React.Component {

    componentDidMount() {
      this.props.onGetCourses();
    }

    ...

}
Sign up to request clarification or add additional context in comments.

12 Comments

I already edited the question with extra information. courses is definitely an array. i have test it out and it return an array of objects.
But for some reason i thing the problem is with the reducers or the action is not firing at all
@sinusGob Thanks for sharing the rest of the code! I've edited my answer, you had an error in the component.
In reducer is it correct? now there is no error but the array appear to be empty. I believe the action is not even call, because there is no event triggering it.
How do i properly do a GET in react-redux?
|
2

its because props sometime can be undefined so you have to write a condtion like this

allCourses() {
     if(this.props.courses){
    return this.props.courses.map((course) => {
      return(
        <li>{ course.name }</li>
      );
    });
   }
   else {
   return []; 
  }

2 Comments

the props is undefined. Is it because my action is not firing ?
yes that can be the case, you can use the redux devtools extension to check if your action getting fired or not , also you should pass the initial state in such a way that you can check if props are filled with data or not.

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.