Avoid refetching data in NextJS when navigating

Thomas Kjær-Rasmussen
4 min readJun 2, 2021

Todays web is all about performance, so how do we squeeze that last bit of speed out of NextJS?

Let’s say you’ve created a cool blog based on a CMS like wordpress using headless and nextJS. It could look something like this

You’ve worked tirelessly on the project for weeks and it’s finally coming together.

But you notice that there's a distinct lag between page transitions, one that you aren’t used to from your old single page application based projects. Every time a person clicks to navigate, the entire page reloads.

So looking at your website you’ve set up the basic structure (This is just for illustrational purposes — but if you want to get your hands dirty heres the code shared on github, the full project is shared in the end)

A catch-all route […index.js] that will catch anything that reaches your next server — within this you have a rendering template:

[…index.js]

For fetching the data you use, getServersideProps() within [...index].js. Like this:

Fetching the navigation data and current page content separately and finally passing it to the page component as props.

So why is the navigations so slow?

First off, we need to start using next’s built in linking system that comes bundled with next by importing

and implementing it in the header component

Full Github Gist can be found here.

The links are now using nexts internal routing engine avoiding a full reload of the page. However, the page navigation is still wait until getServersideProps is ran.

Avoiding Unnecessary Fetches

To speed things up here our strategy should be to only fetch what we actually need. The navigation has already been fetched once, the key to optimizing performance is to avoid fetching anything we don’t need.

First we need to save the data for the navigation somewhere, and then we need to avoid calling the endpoint if we have already fetched the data.

So let us start by storing our navigation data somewhere in a local state

So instead of using the navigation directly, we use it from the local state “stateNavigation” that is set once the page component is mounted.

Now all we have to do is to avoid refetching the navigation data. In order to do that, we can distinct whether the user is navigating directly to a page from outside or internally within the next app.

We do this by looking at the request url (context.req.url), going to localhost:3000/contact for example.

Navigating internally, having already loaded the navigation once would result in "/_next/data/development/contact.json?index=contact"

Otherwise "contact"

Therefore we can check whether the request url starts with /_next/data, and skip the call all together, trusting that our first fetched data is still valid. This saves a call making page transitions much faster.

You can clone the final project on github and see it live on vercel.

Conclusion

This is a neat little trick that makes your next app feel a lot more like a single page application by only loading stale data only once. Use with caution though, if you have data that changes often and is crucial for the end user don’t use this approach.

Happy Hacking!

After thoughts and further reading

There are several approaches to speed up API calls with stale data and this only one of them. You should choose the one that makes sense for your use case. Notably i see a lot of people caching on API level or making a local cache as Flavio Scopes writes in his excellent article How to cache all data in NextJS globally all pages at build time.

NextJS’s own documentation is also a great place to start, notably for this article: Routing and Data Fetching.

👋 Hey! I’m Thomas Kjær-Rasmussen, I head a team of awesome developers making websites for BankData and sometimes i write about it too. Hit me up on Twitter or below if you got any questions, comments or anything in between!

--

--