1

To fill the content of React component I use AJAX request in the body of the method componentWillMount, where I change this.state as a result of the execution of the request. The trouble is that the render method runs as before the request completion, as after the this.state change by setState. Moreover, if such component renders one, which also is used AJAX, the number of render calls grows as a power of two.

How to make the component is rendered only after obtaining the necessary data?

var News = React.createClass({
    getInitialState: function () {
        return {
            news: [],
            page: 1
        };
    },

    componentWillMount: function () {
        let xmlhttp = getXmlHttp();
        xmlhttp.open("POST", "server/news.php", true);
        xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xmlhttp.onreadystatechange=() => {
            if (xmlhttp.readyState != 4) return;
            clearTimeout(timeout);
            if (xmlhttp.status == 200) {
                this.setState({
                    news: eval(xmlhttp.responseText.toString())
                });
            } else {
                handleError(xmlhttp.statusText);
            }
        };
        xmlhttp.send('page=' + this.state.page);
        var timeout = setTimeout( function(){ xmlhttp.abort(); handleError("Request time over") }, 10000);
    },

    render: function () {
        let itemList = this.state.news.map(function(item, iterator){
            return (
                <NewsItem
                    niTitle={item[0]}
                    niText={item[1]}
                    niDate={item[2]}
                    niImg={item[3]}
                    key={"ni " + iterator}
                />
            );
        });
        return (
            <div>
                {itemList}
                <PageChanger page={this.state.page}/>
            </div>
        );
    }
});
1
  • @svnav You might consider passing props from <News> to <PageChanger>, and making batch API calls from <News>, or a wrapping controller component. Commented Sep 21, 2016 at 21:37

2 Answers 2

3

How to make the component is rendered only after obtaining the necessary data?

If your render function returns false, nothing will be rendered. (Source: the docs.)

Therefore, you can set a flag in your initial state:

getInitialState: function () {
    return { page: 1, shouldRender: false };
}

Then, in render, you can check that flag:

if (! this.state.shouldRender) return false;

In the callback passed to the XHR, you can update the flag:

this.setState({
  shouldRender: true,
  news: eval(xmlhttp.responseText.toString()),
});
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. I' ve forgot this from the documentation.
-1

First, abstract your network call to a helper and import into the component as needed.

Second, use componentDidMount not componentWillMount to avoid multiple renders.

for example:

import networkCall from ../helpers/networkCall 
    componentDidMount() {
        this.setState({
            emails: networkCall.news,
            emailCache: networkCall.page
        });
    },

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.