Marko Jakic
Posted on June 8, 2023
Since Next.js released version 13.4 we have the option to render React components on the server. These are called React Server Components (RSC).
This tutorial will show you the way to load JSON content over HTTPS and render it in the server components, caching included. For storing JSON data and fetching it, we'll use nodb API.
For data fetching in Next.js we'll be using actions. This means we'll have to enable experimental features - in next.config.js
first add serverActions
experimental flag:
experimental: {
serverActions: true,
}
This is major prerequisite before we proceed any further. Without this flag nothing will work, but in the next version of Next.js we'll probably already have stable version for actions to use in production.
In Next.js we can use fetch for all HTTP and HTTPS requests within our app. Next.js will cache any request used by fetch
, meaning you don't make new request on each page load. This leads us to another important feature of revalidating cache. I tend to use revalidation of tags, compared to paths. This is because we can have multiple requests on the same page, but we only want SOME requests to be cached. That's why I tag the requests and later revalidate using revalidateTag
function. If your case means you want to revalidate everything on the same page, feel free to use revalidatePath
then.
Now let's see how can we send requests to nodb
to store and fetch data. It's simple really. To store data in nodb
you make a POST request and send array of objects as the payload (even if it's only one object):
await fetch(
`https://api.nodb.sh/your-app/dev/items`,
{
method: 'POST',
body: JSON.stringify([item]),
headers: { token: '...your access token' },
next: { tags: ['items'] },
}
);
See nodb docs to learn how to use apps and environments.
For body
we must send "stringified" version of the payload. For details take a look at Request API examples. It says:
Note: The body can only be a Blob, an ArrayBuffer, a TypedArray, a DataView, a FormData, a URLSearchParams, a ReadableStream, or a String object, as well as a string literal, so for adding a JSON object to the payload you need to stringify that object.
To tag and later revalidate cached data, we add Next.js extended option { next: { tags: ['anystring'] } }
.
In page.js
files we usually make GET requests. In my example project I've got the data from nodb
like this:
const req = await fetch(
`https://api.nodb.sh/[app-name]/[env]/items?__sort_by=itemName`,
{
method: 'GET',
headers: { token: `[token]`,
next: { tags: ['items'] }
}
);
const { items = [] } = await req.json();
This way we just map the items to React components.
Actions
Let's say we want to delete all items. In nodb
we can make a DELETE request to either /items
path to delete them all, or /items/:itemId
to delete a single entity.
For each request made by the user by clicking a button for example, we make actions.
So, if we want to delete all items, we make a file actions.js
in /src/app
(or /app
) dir in our Next.js project, but you can put it anywhere really, e.g. in /src/actions
dir. Inside this file we put the following:
'use server'
export const deleteAllItems = async () => {
await fetch(
`${nodbUrl}/items`,
{ method: 'DELETE', headers, next: { tags: ['items'] } });
revalidateTag('items');
}
Notice here two things. Actions must be called by the server. In Next.js we tell the framework to do exactly that by putting 'use server'
on top of the file, or inside a function. The other thing is that finally here we use revalidateTag
function. After calling this function you'll see on your page.js
file how they're all gone. 😊
The frontend part
Server functions, pages or layouts can't call React hooks or DOM events like onClick
. For that we need client components, the ones which will be loaded in the browser.
In our page.js
let's import a button which will call action to delete all items. First we create a client component:
// /app/components/delete-all-button.js
'use client'
import { deleteAllItems } from '@/app/actions';
export default function DeleteAllItems() {
return (
<button onClick={deleteAllItems}>
Delete all
</button>
);
}
In Next.js we can import server functions inside client files. The result of onClick
will delete all the items and your page will re-render automatically due to revalidateTag
being called in deleteAllItems
server function.
Conclusion
This way we can work with Server Components and fetching data using fetch
built-in mechanism. To store and fetch JSON data you can use any service, it's up to you really.
I hope you found this post helpful and meaningful.
You can find example project which I made to reflect on this post. You can find it at https://github.com/nodb-sh/next-nodb-example.
Posted on June 8, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.