Data Fetching

With the release of Next.js 13, we have two ways to fetch data: fetch() and server actions. Both approaches allow you to fetch and cache data in server components and client components. For now, we will focus on server actions.

Fetching data with server actions

Fetching data with server actions is a straightforward process. To fetch data, all you need to do is create a server action and return the desired data.

async function getData() {
  "use server"
  const data = // fetch data from DB
 
  return data
}
 
export default async function Page() {
  const data = await getData()
  // ...
  return (
    <div>
 
    </div>
  );
}

Example

Let's create a simple blog post example to demonstrate how to fetch data. In the next section, Caching and Revalidating (opens in a new tab), we will continue using this example.

Static page

Static pages contain fixed content that doesn't change based on user input or parameters. They are ideal for displaying information that remains the same for all visitors.

const data = [
  {
    title: "Title 1",
    body: "Lorem ipsum dolor sit amet."
  },
  {
    title: "Title 2",
    body: "Consectetur adipiscing elit, sed do eiusmod tempor incididunt."
  },
  {
    title: "Title 3",
    body: "Ut labore et dolore magna aliqua."
  },
  {
    title: "Title 4",
    body: "Sed ut perspiciatis unde omnis iste natus error."
  },
];
 
async function getData() {
  "use server"
 
  return data
}
 
export default async function Page() {
  const data = await getData()
 
  return (
    <div className="container mx-auto">
      <div className="grid grid-cols-2 gap-4">
        {data.map((item, index) => (
          <div
            key={index}
            className="bg-white p-4 shadow rounded-lg"
          >
            <h2 className="text-lg font-bold mb-2">{item.title}</h2>
            <p className="text-gray-700">{item.body}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

Dynamic page

With dynamic routes, we can retrieve data specific to each route by using dynamic segment [id] which is passed as the params prop to the page.

import { notFound } from "next/navigation";
 
const data = [
  {
    id: 1,
    title: "Title 1",
    body: "Lorem ipsum dolor sit amet."
  },
  {
    id: 2,
    title: "Title 2",
    body: "Consectetur adipiscing elit, sed do eiusmod tempor incididunt."
  },
  {
    id: 3,
    title: "Title 3",
    body: "Ut labore et dolore magna aliqua."
  },
  {
    id: 4,
    title: "Title 4",
    body: "Sed ut perspiciatis unde omnis iste natus error."
  },
];
 
async function getData(id: string) {
  const postId = parseInt(id) || 0;
  const post = data.find(item => item.id === postId);
 
  if (post) return post
  else return null
}
 
export default async function Page({ params }: { params: { id: string } }) {
  const data = await getData(params.id);
  // If a blog post is not found we render a 404 page
  if (!data) notFound()
 
  return (
    <div className="container mx-auto">
      <div
        className="bg-white p-4 shadow rounded-lg"
      >
        <h2 className="text-lg font-bold mb-2">{data.title}</h2>
        <p className="text-gray-700">{data.body}</p>
      </div>
    </div >
  );
}