Need a backend / API for your project? No problem.
One of the game-changers about Next is how is provides an all-in-one solution for creating full-stack React apps by giving you the ability to write server code using a feature called API routes.
To write your backend, add a folder called "api" in /pages to create your own API that are ultimately executed as separate serverless functions.
If we wanted to fetch data for our about page from /api/about, we would include a page called about.js in /pages/api:
// syntax is very similar to the "Express" Node.js framework // here we are responding to every request with an OK (200) code and sending JSON data back (our name) export default function handler(req, res) { res.status(200).json({ name: "Reed Barger" }); }
Now that we have an API route, how do we use it?
How do we request data from our API routes and use the data in our client pages?
The traditional approach would be to request it using useEffect
and useState
:
import Link from "next/link"; import { useEffect, useState } from "react"; export default function About() { const [data, setData] = useState(null); const [isLoading, setLoading] = useState(false); useEffect(() => { setLoading(true); fetch("api/about") .then((res) => res.json()) .then((data) => { setData(data); setLoading(false); }); }, []); if (isLoading) return <p>Loading...</p>; if (!data) return <p>No about data</p>; return ( <div> <h1>My name is: {data.name}</h1> </div> ); }
This approach works, but requires a lot of boilerplate code. On top of that, it doesn't have the best user experience.
While this is a basic example, if we had necessary dynamic info to fetch and display in our pages, we would always show the "Loading" text to our users on every page visit.
An improved way to fetch data and catch it upon future visit is to use the library SWR, which is also made by the developers of Next.
It gives us a convenient hook useSWR
to more easily fetch data and handle loading and errors state, as well as cache data for future visits if nothing has changed. If it has changed, fetch the data in the background while the stale data is shown from the cache.
Note: The hook is named after this "cache invalidation" strategy: "stale-while-revalidate"
Here is the same request made using SWR:
import useSWR from "swr"; const fetcher = (...args) => fetch(...args).then((res) => res.json()) export default function About() { const { data, error } = useSWR("/api/about", fetcher) if (error) return <div>Error fetching data</div> if (!data) return <div>Loading...</div> return ( <div> <h1>{data.name}</h1> </div> ) }
What's an even better way to fetch data in Next that improves user experience and SEO overall?
There are two functions that you can include directly within your page files that allow us to fetch data from the server:
Yes, these functions are in the same file as our React components, but the code for them is bundled separately from our React client.
getServerSideProps
getStaticProps
getServerSideProps
runs on every page visit. As a result, it is very helpful on pages with dynamic data or needs requests to be performed every time, such as getting authenticated user data.
export default function About({ name }) { return ( <div> <h1>My name is: {name}</h1> </div> ); } export function getServerSideProps() { return { props: { name: "Reed Barger" }, }; }
The function does exactly as its name states – it lets us send data from the server and injects it into our page component's props.
What is great about this feature is that it allows our React client to display the data immediately, with no delay, plus not have to handle any loading or error state.
If we wanted to fetch data from the server, we could do so by making getServerSideProps
async using the async
keyword.
export default function About({ name }) { return ( <div> <h1>My name is: {name}</h1> </div> ); } export async function getServerSideProps() { const data = await fetch("https://randomuser.me/api").then((res) => res.json() ); return { props: { name: data.results[0].name.first }, }; }
Here we are dynamically fetching data from the
, and our data changes every time we refresh the page.
Let's rename our getServerSideProps
function with the name getStaticProps
.
Again, the function does what its name says. Or does it?
getStaticProps
is a function that is more appropriate for more static pages that change less frequently. This function executes our server code and makes a GET request on the server, but it only does so once when our project is built.
When you run the app in development, however, it seems to request data every time we refresh the page like getServerSideProps
.
It's important to note that getStaticProps
only makes requests on every page visit during development.
If you run yarn build
and then run the production build or your React project using yarn start
, you will see that no matter how many times we refresh, we keep getting the same name – the name that was requested when the project was built and not at runtime.
Sample result requested from getStaticProps
You might be asking at this point: "Why use API routes at all with these two functions?"
It's important to be aware of the fact that both getServerSideProps
and getStaticProps
can only perform GET requests. API routes can handle any type of request to read and update data (that is when combined with a data layer like a database)
What we've covered here just scratches the surface of Next, but you've already gained everything you need to start using Next in your React projects today.
If you want a more in-depth and technical guide, the official site has an
on how to learn Next.js from the ground up.
The (free) Next.js Learn Course
React is hard. You shouldn't have to figure it out yourself.
I've put everything I know about React into a single course, to help you reach your goals in record time:
Introducing: The React Bootcamp
It’s the one course I wish I had when I started learning React.
Click below to try the React Bootcamp for yourself: