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?
Axios is a Promised-based JavaScript library that is used to send HTTP requests. You can think of it as an alternative to JavaScript's native fetch() function. We will be using features such as Promises, async/await , and other modern JavaScript design patterns in this tutorial.
Axios is a promise based HTTP client for the browser and Node. js. Axios makes it easy to send asynchronous HTTP requests to REST endpoints and perform CRUD operations. It can be used in plain JavaScript or with a library such as Vue or React.
Two issues jump out:
Your getData
never returns anything, so its promise (async
functions always return a promise) will be fulfilled with undefined
if it doesn't reject
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> ); } }
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> ) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With