Use Async/Await with Axios in React.js

JavascriptJsonReactjsAsynchronousEcmascript 2017

Javascript Problem Overview


Following

How to use async/await with axios in react

I am trying to make a simple get request to my server using Async/Await in a React.js App. The server loads a simple JSON at /data which looks like this

JSON

{
   id: 1,
   name: "Aditya"
}

I am able to get the data to my React App using simple jquery ajax get method. However, I want to make use of axios library and Async/Await to follow ES7 standards. My current code looks like this:

class App extends React.Component{
 async getData(){
     const res = await axios('/data');
     console.log(res.json());
 }
 render(){
     return(
         <div>
             {this.getData()}
         </div>
     );
 }
}

Using this approach I get the following error:

> Objects are not valid as a React child (found: [object Promise]). If > you meant to render a collection of children, use an array instead.

Am I not implementing it correctly?

Javascript Solutions


Solution 1 - Javascript

Two issues jump out:

  1. Your getData never returns anything, so its promise (async functions always return a promise) will be fulfilled with undefined if it doesn't reject

  2. The error message clearly shows you're trying to directly render the promise getData returns, rather than waiting for it to settle and then rendering the fulfillment value

Addressing #1: getData should return the result of calling json:

async getData(){
   const res = await axios('/data');
   return await res.json();
}

Addressig #2: We'd have to see more of your code, but fundamentally, you can't do

<SomeElement>{getData()}</SomeElement>

...because that doesn't wait for the resolution. You'd need instead to use getData to set state:

this.getData().then(data => this.setState({data}))
              .catch(err => { /*...handle the error...*/});

...and use that state when rendering:

<SomeElement>{this.state.data}</SomeElement>

Update: Now that you've shown us your code, you'd need to do something like this:

class App extends React.Component{
    async getData() {
        const res = await axios('/data');
        return await res.json(); // (Or whatever)
    }
    constructor(...args) {
        super(...args);
        this.state = {data: null};
    }
    componentDidMount() {
        if (!this.state.data) {
            this.getData().then(data => this.setState({data}))
                          .catch(err => { /*...handle the error...*/});
        }
    }
    render() {
        return (
            <div>
                {this.state.data ? <em>Loading...</em> : this.state.data}
            </div>
        );
    }
}

Futher update: You've indicated a preference for using await in componentDidMount rather than then and catch. You'd do that by nesting an async IIFE function within it and ensuring that function can't throw. (componentDidMount itself can't be async, nothing will consume that promise.) E.g.:

class App extends React.Component{
    async getData() {
        const res = await axios('/data');
        return await res.json(); // (Or whatever)
    }
    constructor(...args) {
        super(...args);
        this.state = {data: null};
    }
    componentDidMount() {
        if (!this.state.data) {
            (async () => {
                try {
                    this.setState({data: await this.getData()});
                } catch (e) {
                    //...handle the error...
                }
            })();
        }
    }
    render() {
        return (
            <div>
                {this.state.data ? <em>Loading...</em> : this.state.data}
            </div>
        );
    }
}

Solution 2 - Javascript

In my experience over the past few months, I've realized that the best way to achieve this is:

class App extends React.Component{
  constructor(){
   super();
   this.state = {
    serverResponse: ''
   }
  }
  componentDidMount(){
     this.getData();
  }
  async getData(){
   const res = await axios.get('url-to-get-the-data');
   const { data } = await res;
   this.setState({serverResponse: data})
 }
 render(){
  return(
     <div>
       {this.state.serverResponse}
     </div>
  );
 }
}

If you are trying to make post request on events such as click, then call getData() function on the event and replace the content of it like so:

async getData(username, password){
 const res = await axios.post('url-to-post-the-data', {
   username,
   password
 });
 ...
}

Furthermore, if you are making any request when the component is about to load then simply replace async getData() with async componentDidMount() and change the render function like so:

render(){
 return (
  <div>{this.state.serverResponse}</div>
 )
}

Solution 3 - Javascript

  useEffect(() => {     
    const getData = async () => {  
      await axios.get('your_url')  
      .then(res => {  
        console.log(res)  
      })  
      .catch(err => {  
        console.log(err)  
      });  
    }  
    getData()  
  }, [])

Solution 4 - Javascript

const axios = require('axios').default;

const sendGetRequest = async () => {
    try {
        const resp = await axios.get('https://jsonplaceholder.typicode.com/posts', {
            headers: {
                'authorization': 'Bearer YOUR_JWT_TOKEN_HERE'
            }
        });

        console.log(resp.data);
    } catch (err) {
        // Handle Error Here
        console.error(err);
    }
};

sendGetRequest();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSinghView Question on Stackoverflow
Solution 1 - JavascriptT.J. CrowderView Answer on Stackoverflow
Solution 2 - JavascriptSinghView Answer on Stackoverflow
Solution 3 - JavascriptFelipe CorredorView Answer on Stackoverflow
Solution 4 - JavascriptMD SHAYONView Answer on Stackoverflow