Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React component with ajax call - life-cycle

So I have an interesting case of using react with Ajax call.

To put it in the context, I have an accordion with 3 tabs. After initializing Accordion react component, I have the first tab initially open, the rest is closed. Every tab has in it's body so called DictionaryCall component which looks like this:

return class DictionaryCall extends React.Component {

        constructor (props) {
            super();
            this.state = {
                word: '',
                data: [],
                error: false,
                nodata: false,
                initialLoaded: props.load
            }
        }

        componentDidMount () {
            if(this.state.initialLoaded){
                this.callAjax();
            }
        }

        componentWillReceiveProps (nextProps) {
            if(nextProps.load){
                this.setState({initialLoaded: true});
                this.callAjax();
            }
        }

        callAjax () {
            $.ajax({
                url: this.props.url,
                dataType: 'json',
                catche: false,
                method: 'POST',
                data: {word: this.props.word},
                success: function(data){
                    if(!data.length){
                        this.setState({nodata: true});
                    } else {
                        this.setState({data: data});
                    }
                }.bind(this),
                error: function(xhr, status, error){
                    console.log(this.props.url, status, error.toString());
                    this.setState({error: true});
                }.bind(this)
            });
        }

        render () {
            let body,
                error = this.state.error;

            if(this.state.nodata){
                body = <div>No definition found</div>
            } else {
                body = <DataTab data={this.state.data} title={this.props.word}/>
            }

            return (
                <div className="dictionary-call">
                    {body}
                    {error ? <ServerError onClick={this.callAjax.bind(this)}/> : null}
                </div>
            )
        }
    };

Fist of all according to React docs setting initial state with props is an anti-pattern, until you specify explicitly it's only for component initialization.

So as it can be seen in the constructor, I'm setting initialLoaded state with props.load. I'm passing props.load as true only to the first Accordion tab as I want it to be loaded initially.

componentDidMount method is called and checks initialLoaded state. If it's set to true it simply calls ajax and re-render the component.

Now the tricky bit. The componentWillReceiveProps method. I'm expecting, the component will receive nextProps.load when user clicks on the Accordion tab to open it. Then props.load is passed to the component with true value.

My question is, is componentWillReceiveProps a good place to call this.callAjax() ? It seems a bit pointless to create the initalLoaded state in this case. Shouldn't I simply base on props.load instead and call shouldComponentUpdate ?

Or maybe I should stick with initalLoaded state and use componentWillUpdate or componentDidUpdate.

Bear in mind I want to call ajax call only once when the accordion tab gets opened for the first time.

Thanks!

like image 810
matewilk Avatar asked May 01 '16 16:05

matewilk


People also ask

In which life cycle method it is advisable to make a AJAX call in React?

According to official React docs, the recommended place to do Ajax requests is in componentDidMount which is a lifecycle method that runs after the React component has been mounted to the DOM.

Where in the component lifecycle should I make an AJAX call?

Where in the component lifecycle should I make an AJAX call? You should populate data with AJAX calls in the componentDidMount lifecycle method. This is so you can use setState to update your component when the data is retrieved.

How many times componentDidMount runs in a life span of a component?

2. How many times componentDidMount is called? React components call componentDidMount only once by default. You can run the component multiple times if you delete the component or change the props or state.


1 Answers

So after a bit of research I want to answer my own question. Hope it helps someone.

The solutions is very simple and clean (in my opinion).

        componentDidMount () {
            if(this.state.initialLoaded){
                this.callAjax();
            }
        }

        componentWillReceiveProps (nextProps) {
            if(nextProps.load){
                this.setState({initialLoaded: true});
            }
        }

        componentWillUpdate (nextProps, nextState) {
            if(this.state.initialLoaded !== nextState.initialLoaded) {
                this.callAjax();
            }
        }

This code applies to all instances of the component, no matter if it is a child of the first accordion tab (initially open) or the rest of tabs (initially closed).

In componentDidMount method, I'm checking if component should make an Ajax call. If during the initialization the this.props.open has set the this.state.initialLoaded state to true, than the ajax call is made. Otherwise of course not.

Now, when user clicks other tab, the component is expecting props in componentWillReceiveProps. Here I'm setting state only if nextProps.load is true, as I want to potentially load the data only if load field is true.

Lastly, if the condition in componentWillReceiveProps has been met, I'm checking if this.state.initialLoaded has changed. As it could be changed only when nextProp.load is true, it prevents from calling Ajax requests too many times (when state changes from true to false).

This way, I'm calling the Ajax request only when the tab is opened for the first time, or when it is initially opened.

That simple!

like image 99
matewilk Avatar answered Oct 23 '22 04:10

matewilk