Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React best way to handle empty object before mount?

I have a React class, and it wants to render an object shown below:

data: {
    title: "haha",
    description: {
        country: "US",
        year: "1996"
    }
}

But, when React wants to render it, it gives an error.

Uncaught Error: Invariant Violation: receiveComponent(...): Can only update a mounted component

I think the problem is in the getInititalState, I declare my data as an empty object, so when I get my full data object after the timeout, React will try to map my data object to the component, but it gives error.

But one interesting thing is, I have no problem accesing this.props.title.title, but not this.props.title.description.country, it will give undefined

But, when I console.log it, I could see my object. But React cant access it!

My guessing is when React initializing from the empty object, it will only init the virtual DOM with the 1st and 2nd level of the data object.

That the reason, when I try to access this.props.data.data.title is OK but not this.props.data.data.description.country

Below is my code

var BookBox = React.createClass({
    getInitialState: function() {
        return { data: {} };
    },
    componentWillMount: function() {
        var that = this;
        setTimeout(function() {
            console.log('timeout');
            that.setState({
                data: {
                    title: "haha",
                    description: {
                        country: "US",
                        year: "1996"
                    }
                }
            });
        }, 2000);
    },
    render: function() {
        return (
            <div>
                <h1>{this.state.data.title}</h1>
                <TestBox title={this.state.data} />
            </div>
        );
    }
});

var TestBox = React.createClass({
    render: function() {
        console.log(this.props.title);
        return (
            <div>
                <p>{ this.props.title.description.country }</p>
                <p>{ this.props.title.title }</p>
            </div>
        );
    }
})

May I know what is the best way to handle this problem? should i init my data object structure in the getInitialState or there is a better way?

like image 328
Tim Avatar asked Sep 28 '22 17:09

Tim


1 Answers

I think you are getting Can only update a mounted component error because you are using componentWillMount and settimeout together, but you dont know if the component has been mounted by the time settimeout function fires.

Since you know what your state is beforehand, I think it is best to return your data from getInitialState function.

You can also use componentDidMount instead of componentWillMount function. That way you can be sure the component is mounted when componentDidMount is called.

Any time time you are using asycn functions like settimeout or a xhr call, you should use this.isMounted() in the callback function, to check that the component is still mounted by the time the callback fires.

For example, if you didnt know the state beforehand, you could fire an xhr call in the componentDidMount function, check this.isMounted() in the success callback and setState.

As for the error on <p>{ this.props.title.description.country }</p> line: At initial render this.state.data (BookBox) is an empty object so is this.props.title(TestBox). Accessing empty object's ({ }) title property is undefined. No problem there. Accessing description is also undefined. But accessing undefined's country is error. To avoid this error you can create a description variable: description = this.props.title.description || {} and use <p>{description.country}</p> to make sure your code doesnt break if this.props.title is empty.

like image 87
nilgun Avatar answered Oct 02 '22 15:10

nilgun