简体   繁体   中英

React with Redux: error on propType property

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM