I'm new in the React world. I got a course to training React and Redux. Like yesterday I got an error while I'm attending an online training Even though, I walk through the author course and copy the code from the screen I get an error:
Warning: Failed propType: Required prop courses
was not specified in CoursesPage
. Check the render method of Connect(CoursesPage)
.
I have uploaded my code to github: https://github.com/tarcisiocorte/reactredux/blob/master/src/components/course/CoursesPage.js
again....I will appreciate some help.
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:{title: ""} }; 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}); } courseRow(course, index){ return <div key={index}>{course.title}</div>; } onClickSave() { this.props.dispatch(courseActions.createCourse(this.state.course)); } render() { return ( <div> <h1>Courses</h1> {this.props.courses.map(this.courseRow)} <h1>Add Courses</h1> <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);
In https://github.com/tarcisiocorte/reactredux/blob/master/src/index.js#L11
You need to specify a default for courses.
You have specified that your courses
prop is required:
courses: PropTypes.array.isRequired
so you need to pass in something from the redux store and by the looks of it the courses
property in your redux store is undefined
. (Put a breakpoint here to check that is actually the case)
You can either make sure your redux store always returns something for your courses
or your can remove the isRequired
constrain:
CoursesPage.propTypes = {
dispatch: PropTypes.func.isRequired,
courses: PropTypes.array
};
In your 'Routes' component, you'll want to change
<Route path="courses" component={CoursesPage} />
to
<Route path='courses' render={(stuff) => (
<CoursePage courses={stuff} />
)}/>
When you use component, you can't add your required props, so render would be a good alternative. This also means you'll have to add redux connections to your routes.js since you need to get that information from somewhere.
Another, more simpler, solution would be just to eliminate courses as a prop and get that information directly from redux when CoursePage loads up. You've already done half the battle with your mapStateToProps, therefore you dont need to have it with the "isRequired" in your propTypes. This is basically when Klugjo said, so if you decide to take this approach, give him credit.
I'd also hazard a guess that if 'courses' in your store doesn't exist, your isRequired is being triggered as well. So you might be able to keep isRequired as long as you have your data for that prop in the store.
For anyone coming across a similar failed prop type error, such as below, or if the other answers did not resolve your issue, the following might be an alternate fix for you. In the context of user428745
's post above, someProjects
and ResponsiblePage
in the error below would correspond to the courses
prop (some array of values) and the CoursesPage
component, respectively.
Given user428745
's setup below
CoursesPage.propTypes = {
dispatch: PropTypes.func.isRequired,
courses: PropTypes.array.isRequired
};
function mapStateToProps(state, ownProps) {
return {
courses: state.courses
};
}
The issue might be related to how the redux state gets the state.courses
value in the first place. In my case, the prop (ie. courses
as in state.courses
) in mapStateToProps
was being set before the data was available from the redux store. This happened due to an API data call that had not yet finished. My fix was:
function mapStateToProps(state, ownProps) {
return {
courses: state.courses || [] // Equivalent to statement below
//courses: state.courses == null ? [] : state.courses
};
}
If state.courses
is null (due to API data not loaded yet) we return []
to satisfy the array
requirement on our prop. If it is valid, which means the data was available and was put inside of state.courses
, then we simply return state.courses
similar to before.
Note also that there might be different required configuration setups (to make redux work properly), ie. depending on how you link your reducer(s) to your root reducer (which would be the content in index.js
inside of reducers
folder). If the error is still not fixed with these changes, try another approach with the root reducer, such as:
// From this (see `user428745`'s source files, where 'courseReducer' was imported as 'courses')
export default combineReducers({
courseReducer
});
// To this
export default combineReducers({
rootReducer: courseReducer
});
// Where 'mapStateToProps' would also have to change
function mapStateToProps(state, ownProps) {
return {
courses: state.rootReducer.courses || []
};
}
And where you intend to use this value, ie. with this.props.courses
or props.courses
in your CoursesPage
setup, you could console log the values (or whatever you wanted to do) only when the array is not empty:
if (props.courses.length > 0) {
console.log(props.courses);
}
Or maybe listen to props.courses
changes so that you perform something only "in the moment" after it changes (whereas the if
statement above would be valid at all times, from when the prop was filled with values):
useEffect(() => {
if (props.courses.length > 0) {
console.log(props.courses);
}
}, [props.courses]);
Note that if you use useEffect
, make sure it is within your CoursesPage
component, and not in the "root" of the file where you would ie. write export default CoursesPage
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.