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.
The "Cannot read property 'props' of undefined" error occurs when a class method is called without having the correct context bound to the this keyword. To solve the error, define the class method as an arrow function or use the bind method in the classes' constructor method.
The "cannot read property 'map' of undefined" error occurs when we call the map() method on an undefined value, most often when the map method is called before the data from an API request has arrived. To solve the error, initialize the value you're mapping over to an empty array.
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();
}
...
}
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 [];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With