React - Axios/Fetch/Ajax request after new props passed to child component

Viewed 1229

I have two components, App and Child. My goal is that App passes an id down to Child and when Child receives it as props, I want Child to perform an Axios/Fetch request and then update itself with the result data. I will accept any answer that provides me with an example App/Child source code that completes my example or gives my insight if this is actually possible what I'm trying to implement.

I am a new to React.

// App.js

import React, { Component } from 'react';
import Child from './Child.js';
import './App.css';

class App extends Component {

  state = {
    id: 0
  };

  handleClick() {
    this.setState({
      id: this.state.id + 1
    });
  }

  render() {
    return (
      <div>
        <Child id={this.state.id} />
        <div>
          <button onClick={this.handleClick.bind(this)}>Pass new id down to Child component</button>
        </div>
      </div>
    );
  }
}

export default App;

// Child.js

import React, { Component } from 'react';
import axios from 'axios';

class Child extends Component {
    state = {
        data: null,
        id: 0
    };

    loadData(q, cb) {
        axios.get('http://localhost:3000/foo?q='+this.state.id)
        .then(result => {            
            // ?
            // this.setState would retrigger update and create an infinite updating loop
        })
        .catch(error => {
            console.log('error: ' + error);
        });
    }

    shouldComponentUpdate(nextProps, prevState) {
        console.log('shouldComponentUpdate: nextProps = ' + JSON.stringify(nextProps) + ', prevState = ' + JSON.stringify(prevState));        

        // ??
    }

    getSnapshotBeforeUpdate(nextProps, prevState) {
        console.log('getSnapshotBeforeUpdate: nextProps = ' + JSON.stringify(nextProps) + ', prevState = ' + JSON.stringify(prevState));

        // ?? 
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        console.log('getDerivedStateFromProps: nextProps = ' + JSON.stringify(nextProps) + ', prevState = ' + JSON.stringify(prevState));
        return {
            id: nextProps.id
        };

        // ?? 
    }

    componentDidUpdate() {
        console.log('componentDidUpdate');
    }

  render() {
    return (
      <div>
          <div>data = {this.state.data}</div>
      </div>
    );
  }
}

export default Child;
2 Answers

You should call check prev Id with current id to avoid recursive update. You just need to make sure you only derive state from props if your props have changed,

static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.id !== prevState.id) {
    return {
        id: nextProps.id
    };
 }
 return null;

}

Let me know if your issue still persists

This could be one way to go about your problem,

Firstly, you'll have to update all the state data inside your getDerivedStateFromProps

static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.id !== prevState.id) {
    // Returning this object is equivalent to setting state using this.setState    
        return {
            id: nextProps.id
            data: loadData(nextProps.id) // Something like this
        };
    }
    return null; // Indicates no state change
}

As for the api call inside loadData method you can make use of the aync / await to return the data from api call

async loadData(id) {
    try {
        // Make your api call here
        let response = await axios.get('http://localhost:3000/foo?q='+id);
        return await response.json();
    } catch(err) {
        // catches errors both in axios.get and response.json
        // Make sure to not update state in case of any error
        alert(err);
        return null;
    }
}

Note:

  • This is not the complete solution as you might want to not update the state in the case where your api call in loadData catches any error.
  • Also, since you are using api calls, you might want to limit the times pass props to the child cause they all will trigger different api calls and you will run into unpredictable states. Try debouncing.
Related