React component not working on page refresh


#1

I’m building an app to help me learn React and have run into a little issue. The app is for generating contests and my ContestPage component is giving me problems. First of all, I load the ContestPageContainer component to get all the data I’ll need for the page.

C.ContestPageContainer = React.createClass({
    propTypes: {
        contest_id: React.PropTypes.string
    },
    mixins: [
         ReactMeteorData
    ],

    getInitialState() {
        return {}
    },
    getMeteorData() {
        var contestId = this.props.contest_id;
        var handle = Meteor.subscribe("contest", contestId);

        return {
            contest: Contests.findOne(contestId),
            contestLoading: ! handle.ready(),
            currentUser: Meteor.user()
        };
    },

   
    shouldComponentUpdate() {
        return true;
    },
    
    render() {
        return (
            <div>
                <C.ContestPage contest={this.data.contest} currentUser={this.data.currentUser}/>
            </div>
        )
    }
});

I pass the contest id to the ContestPageContainer component with FlowRouter.

FlowRouter.route("/contests/:_id", {
    name: "ContestPage",
    subscriptions(params) {

    },
    action(params) {
        renderMainAppWith(<C.ContestPageContainer contest_id={params._id} />);
    }
});

Here is the renderMainAppWith code if you’re interested

function renderMainAppWith(component) {
    ReactLayout.render(C.MainApp, {
        header: <C.Header />,
        content: component,
        footer: <C.Footer />
    });
}

The ContestPageContainer just passes it’s data on to the ContestPage component via props.

C.ContestPage = React.createClass({
    propTypes: {
        contest: React.PropTypes.object,
        currentUser: React.PropTypes.object
    },
    mixins: [],

    getInitialState() {
        return {}
    },
    getMeteorData() {
        
    },

    componentWillMount() {
    },
    componentDidMount() {
    },
    componentWillReceiveProps() {
    },
    shouldComponentUpdate() {
        return true;
    },
    componentWillUnmount() {
    },

    render() {
        return (
            <div className="contest-page-wrapper">
                <h1>{this.props.contest.title}</h1>
            </div>
        )
    }
});

In order to get to the ContestPage component a user must click a link that is dynamically generated in my ContestsList component. The ContestPage component works fine when I click on a list item, however, when I refresh the page (while on a contest page) I get a Type Error stating that the contest prop I passed to the ContestPage is undefined.

Any idea as to what is going wrong?

UPDATE

I just noticed that I am also getting the following error:

Error: Invariant Violation: findComponentRoot(..., .0.0.0.1): Unable to find element. This probably means the DOM was unexpectedly mutated (e.g., by the browser), usually due to forgetting a <tbody> when using tables, nesting tags like <form>, <p>, or <a>, or using non-SVG elements in an <svg> parent. Try inspecting the child nodes of the element with React ID ``.

#2

I figured out my problem… React was throwing an error because I was telling it to display data that had not yet been loaded. So, I added an if block to my ContestPage render block that shows a loading tag if the page is loading.

C.ContestPage = React.createClass({
    propTypes: {
        contest: React.PropTypes.object,
        contestLoading: React.PropTypes.bool,
        currentUser: React.PropTypes.object
    },
    mixins: [],

    getInitialState() {
        return {}
    },
    getMeteorData() {
     
      
    },

    componentWillMount() {
    },
    componentDidMount() {
    },
    componentWillReceiveProps() {
    },
    shouldComponentUpdate() {
        return true;
    },
    componentWillUnmount() {
    },

    render() {
        if (this.props.contestLoading) {
            return (
                    <div>
                        <h1>Loading...</h1>
                    </div>
            );
        }
        return (
            <div className="contest-page-wrapper">
                <h1>Hello {this.props.contest.description}</h1>
            </div>
        )
    }
});

#3

Yea sometimes it can be caused by Meteor loading one file before the other (not sure if that was the case here). Glad you figured it out!