0

When I try to fetch data in NextJS 13 an error encountered Unhandled Runtime Error. what is the Error here.

async function getPosts() {
  const res = await fetch(
    "https://jsonplaceholder.typicode.com/posts?_limit=10"
  );
  if (!res.ok) {
    throw new Error("Unable to fetch data!");
  }
  return res.json();
}
const Posts = async () => {
  const data = await getPosts();
  return (
    <>
      {data.map((post) => {
        return <p>{post.title}</p>;
      })}
    </>
  );
};
export default Posts;

1 Answers1

0

I'm not seeing the same Unhandled Runtime Error as you, but we're probably just using different versions of Next.js.

I don't know how it is for the App router, but if you're using the Pages router then the error you're seeing is likely caused by your async component: you're returning a Promise for the Posts component, which isn't a data type that can be rendered to the page.

Instead, you should update your code so that the data fetching is done in an effect. The result is then parsed and stored in state:

import { useEffect, useState } from "react";

async function getPosts() {
  const res = await fetch(
    "https://jsonplaceholder.typicode.com/posts?_limit=10"
  );

  if (!res.ok) {
    throw new Error("Unable to fetch data!");
  }

  return res.json();
}

// components can't be an async function
const Posts = () => {
  // data should be stored in state for referencing later
  const [data, setData] = useState([]);

  // data fetching occurs in an effect that runs only once on mount
  useEffect(() => {
    async function fetchPosts() {
      const postData = await getPosts();
      setData(postData);
    }
    fetchPosts();
  }, []);

  return (
    <>
      {data.map((post) => {
        return (
          // key is required for iterating over an array
          <p key={post.title}>{post.title}</p>
        );
      })}
    </>
  );
};

export default Posts;

Note that I also added a key attribute to your list to prevent rendering issues. This should be a unique key that ideally isn't simply the index.

If this Posts component could be a page in your case, then another way to handle this data fetching would be to run the fetching at build time using getStaticProps, or on the server at request time using getServerSideProps (if the data is subject to change frequently, which I suppose it won't in this case). Here you can read more about the differences between getStaticProps and getServerSideProps.

If that is a suitable change, here is how you would do it. Note that for this to work, Posts will have to be a page inside of the pages directory:

// this will run on the server at build time. In development, it will run on every request
export async function getStaticProps() {
  const res = await fetch(
    "https://jsonplaceholder.typicode.com/posts?_limit=10"
  );

  if (!res.ok) {
    console.error("Unable to fetch data!");
    return {
      props: {
        data: [],
      },
    };
  }

  return {
    props: {
      data: await res.json(),
    },
  };
}

// components can't be an async function
const Posts = ({ data }) => {
  return (
    <>
      {data.map((post) => {
        return (
          // key is required for iterating over an array
          <p key={post.title}>{post.title}</p>
        );
      })}
    </>
  );
};

export default Posts;
James Hooper
  • 1,475
  • 13
  • 24