How to fetch data after pageload with React Hooks
August 28, 2020
You will often need to fetch data from an API after a page has loaded/rendered when you’re building React applications. A common use case is after rendering some initial data to keep a user engaged while you request additional data from a backend API.
There’s a built-in React hook that provides everything you need to do this: the useEffect()
hook.
If you just need a code example, there’s a GitHub Gist here.
Fetching data after the initial page render with React hooks
My go-to strategy to fetch data after the page has rendered is by using the useEffect()
hook. This hook is used to perform an action after the page has rendered, which is ideal for fetching data.
The below walkthrough assumes you have a React functional component ready to go.
If you’re using VS Code and have emmet enabled, you can create an empty component by typing rsc
+ tab in an empty js file (guide here).
Step 1: Pull out the hook in your import
In your React import, make sure you’re destructuring the useEffect
hook:
import React, { useEffect } from "react"
This isn’t requied, but it makes your code nicer to read and write.
Step 2: Add the hook to your component function
An empty useEffect()
hook will look like the below:
useEffect(() => {
// CODE WILL GO HERE
})
Step 3: Customise the hook so it’s not triggering every time the page rerenders
Out of the box, the useEffect()
hook above will trigger every time the page rerenders.
You probably don’t want your data fetch to trigger on every render. If you’re getting data from an API to hydrate your page, you might only need the data once (on the first pageload).
Adding an empty array after the lambda will cause the function to only trigger on the first render:
useEffect(() => {
// CODE WILL GO HERE
}, [])
The second argument (currently an empty array) is used to trigger the hook. If you added a state item inside the array, it would cause the useEffect()
hook to trigger every time that state item is changed.
Step 4: Add your fetch logic
Now that the hook is up and running, you can add your fetch logic. At the moment, you can’t make the useEffect()
function async directly (by simply adding async
).
For simplicity sake, I’ll use a promise. Your code might look something like the below:
useEffect(() => {
fetch("https://example.com/data")
.then(response => response.json())
.then(data => {
// DO STUFF WITH YOUR DATA
})
}, [])
To use async/await, you need to create a function within the function (there’s a StackOverflow issue about it here).
And you’re done
If you followed the above, you’ve fetched data from an API after your page has rendered the first time. Pair this with a loading useState()
hook and a spinner and you just might have a nice user experience while a 30MB JSON object is being returned.
How was this done before React Hooks?
Below are the ways data was retrieved after the page loaded/rendered before React and in React before hooks.
Quick tip: don’t use the jQuery or Vanilla JS strategies below with React for the sake of your sanity.
Before React
In the days before React, you could trigger an ajax call after the page loaded using jQuery’s .ready
function (paired with the .ajax
function to fetch data).
This looked similar to the below:
$(document).ready(function() {
$.ajax({
url: "https://example.com/data",
success: function() {
// DO STUFF
},
})
})
The above would fire an ajax call after the DOM finished loading.
Or, if you were using Vanilla JS, you could use the window.onload
property:
window.onload = function() {
let xhr = new XMLHttpRequest()
xhr.responseType = "json"
xhr.open("GET", "https://example.com/data", true)
xhr.onload = function() {
let jsonData = JSON.parse(xhr.responseText)
// DO STUFF WITH DATA
}
xhr.send()
}
The above is getting data from an API after the DOM is fully loaded. You could also use fetch()
instead of XMLHttpRequest()
, but that wasn’t available when this was most common.
Both of the above are doing basically the same thing: requesting data from somewhere after the page (DOM) loads.
With React class-based components
If you’re using non-functional React components, you can fire off a request for data after the page has rendered using componentDidMount()
. This method will trigger once the current component has rendered.
This often looks similar to the below:
import React, { Component } from "react"
class App extends Component {
constructor(props) {
super(props)
this.state = {
stuff: "",
}
}
componentDidMount() {
fetch("https://api.example.com").then(response => {
// DO STUFF WITH DATA SUCH AS SETSTATE
})
}
}
export default App
I hope this article helped. If just need an example snippet, you can grab a useable example here.
Written by Josh Amore who lives and works in Melbourne, Australia. You can contact him here.