Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

componentDidMount not called

I have a component that does not appear to be firing the componentDidMount event. The component is a parent that is accessed using react-router Link via another component.

here is my list component and the child components:

CoursesPage

import React from 'react';
import CourseList from './CourseList';
import CourseApi from '../../api/courseApi';

import {browserHistory} from 'react-router';

class CoursesPage extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.state = {
            courses: []
        };
        this.redirectToAddCoursePage = this.redirectToAddCoursePage.bind(this);
    }

    componentDidMount(){
        CourseApi.getAllCourses().then(coursesData => {
            this.setState({ courses: coursesData });
        }).catch(error => {
            throw(error);
        });
    }

    redirectToAddCoursePage() { browserHistory.push('/course'); }

    render() {
        const courses = this.state.courses;
        return (
            <div>
                <div className="page-header">
                    <h3>Courses</h3>
                </div>
                <input type="submit" value="New Course" className="btn btn-default btn-toolbar pull-right" onClick={this.redirectToAddCoursePage} />
                <div className="panel panel-default ">
                    <div className="panel-heading">
                        <span>&nbsp;</span>
                    </div>
                    <CourseList courses={courses} />
                </div>
            </div>        
        );
    }
}

export default CoursesPage;

CourseListRow

import React from 'react';
import PropTypes from 'prop-types';
import CourseListRow from './CourseListRow';

const CourseList = ({courses}) => {
    return (
        <table className="table table-hover">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Title</th>
                    <th>Author</th>
                    <th>Category</th>
                    <th>Length</th>
                </tr>
            </thead>
            <tbody>
                { courses.map(course => <CourseListRow key={course.CourseId} course={course} /> )}
            </tbody>
        </table>
    );
};

CourseList.propTypes = {
    courses: PropTypes.array.isRequired
};

export default CourseList;

CourseListRow

import React from 'react';
import PropTypes from 'prop-types';
import {Link} from 'react-router';

const CourseListRow = ({course}) => {
    return (
        <tr>
            <td><Link to={'/course/' + course.CourseId}>{course.CourseId}</Link></td>
            <td>{course.Title}</td>
            <td>{course.Author.FirstName + ' ' + course.Author.LastName}</td>
        </tr>
    );
};

CourseListRow.propTypes = {
    course: PropTypes.object.isRequired
};

export default CourseListRow;

My routes

import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from './components/App';
import CoursesPage from './components/course/CoursesPage';
import ManageCoursePage from './components/course/ManageCoursePage';

export default (
    <Route path="/" components={App}>
        <IndexRoute component={HomePage} />
        <Route path="courses" component={CoursesPage} />
        <Route path="course" component={ManageCoursePage} />
        <Route path="course/:id" component={ManageCoursePage} />
    </Route>
);

All of the above components work fine. However, when I click on the Link for a course in the CourseListRow component to route to the component below, the state for the course object is always empty. I put a debugger statement in the componentDidMount event and it never hits it, so this components CourseForm child component (not shown) never gets the course:

import React from 'react';
import PropTypes from 'prop-types';
import CourseForm from './CourseForm';
import {authorSelectData} from '../../selectors/selectors';
import CourseApi from '../../api/courseApi';
import AuthorApi from '../../api/authorApi';

export class ManageCoursePage extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.state = {
            course: {},
            authors: [],
        };
    }

    componentDidMount() {
        let id = this.props.params.id;
        if (id) {
            CourseApi.getCourse(id).then(courseData => {
                this.setState({ course: courseData });
            }).catch(error => {
                throw(error);
            });
        }

        AuthorApi.getAllAuthors().then(authorsData => {
            this.setState({
                authors: authorSelectData(authorsData)
            });
        }).catch(error => {
            throw(error);
        });
    }

    render() {
        return (
            <CourseForm 
                course={this.state.course}
                allAuthors={this.state.authors}
            />
        );
    }
}


ManageCoursePage.contextTypes = {
    router: PropTypes.object
};

export default ManageCoursePage;

For the life of me, I cannot figure why componentDidMount is not firing and populating the course state object. Any help is appreciated

Follow up:

I changed my render method of my parent (ManageCoursePage) component to the following, commenting out the CourseForm child compnonent:

render() {
    return (
        <h2>Hi {this.state.course.CourseId}</h2>
        /*<CourseForm 
            course={this.state.course}
            authors={this.state.authors}
            onChange={this.updateCourseState}
            onSave={this.saveCourse}
            onDelete={this.deleteCourse}
            onCancel={this.cancelChange}
            errors={this.state.errors}
            saving={this.state.saving}
            deleting={this.state.deleting}
        />*/
    );
}

This worked, I got "Hi 11". It appears for whatever reason my child component is not receiving the props from my parent. Could this be something to do with react router, that I am missing something? This has me really perplexed

like image 829
steveareeno Avatar asked Mar 10 '23 05:03

steveareeno


1 Answers

I think calling the getCourse in the componentWillReceiveProps and not in ComponentDidMount will solve your issue.

  componentWillReceiveProps(nextProps) {
        var nextId = nextProps.params.id;
        if (nextId !== this.props.params.id) {
                  CourseApi.getCourse(nextId).then(courseData => {
                    this.setState({ course: courseData });
                }).catch(error => {
                    throw(error);
                });
        }
    }
like image 165
radix Avatar answered Mar 31 '23 11:03

radix