admin管理员组

文章数量:1317732

I've been trying to build this blog app, Before is fine and in the dev environment is also fine. But, as soon as i try to build it for production it caught in this error.

Error occurred prerendering page "/blogs/[slug]". Read more: TypeError: Cannot read property 'title' of undefined

I am confused because this app had been build before and nothing is wrong. This is the culprit:

import Head from "next/head";
import "bootstrap/dist/css/bootstrap.min.css";
import ReactMarkdown from "react-markdown";
import moment from "moment";

const Post = ({ posts }) => {
  return (
    <>
      <Head>
        <title>{posts && posts.title}</title>
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0"
        ></meta>
      </Head>
      <div className="container" style={{ marginTop: "3.85rem" }}>
        <div className="row">
          <h1>{posts.title}</h1>
        </div>
        <div className="row d-flex justify-content-end">
          <p style={{ textAlign: "right" }}>
            {moment(posts.dateTime).format("dddd, Do MMMM YYYY, hh:mm:ss a")}
          </p>
        </div>
        <br />
        <div className="row d-flex justify-content-center">
          <img
            className="postThumbNail"
            src={posts.thumbnail.url}
            alt={posts.thumbnail.url}
          />
        </div>
        <br />
        <ReactMarkdown>{posts.body}</ReactMarkdown>
      </div>
    </>
  );
};

export async function getStaticProps({ params: { slug } }) {
  const res = await fetch(
    `=${slug}`
  );
  const blogPost = await res.json();

  return {
    props: {
      posts: blogPost[0],
    },
    revalidate: 600,
  };
}

export async function getStaticPaths() {
  // Get Post From Strapi
  const res = await fetch(
    ";
  );
  const post = await res.json();
  //  Retrun Enrich Content
  return {
    paths: post.map((posts) => ({
      params: { slug: String(posts.slug) },
    })),
    fallback: true,
  };
}

export default Post;

I've been trying to build this blog app, Before is fine and in the dev environment is also fine. But, as soon as i try to build it for production it caught in this error.

Error occurred prerendering page "/blogs/[slug]". Read more: https://nextjs/docs/messages/prerender-error TypeError: Cannot read property 'title' of undefined

I am confused because this app had been build before and nothing is wrong. This is the culprit:

import Head from "next/head";
import "bootstrap/dist/css/bootstrap.min.css";
import ReactMarkdown from "react-markdown";
import moment from "moment";

const Post = ({ posts }) => {
  return (
    <>
      <Head>
        <title>{posts && posts.title}</title>
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0"
        ></meta>
      </Head>
      <div className="container" style={{ marginTop: "3.85rem" }}>
        <div className="row">
          <h1>{posts.title}</h1>
        </div>
        <div className="row d-flex justify-content-end">
          <p style={{ textAlign: "right" }}>
            {moment(posts.dateTime).format("dddd, Do MMMM YYYY, hh:mm:ss a")}
          </p>
        </div>
        <br />
        <div className="row d-flex justify-content-center">
          <img
            className="postThumbNail"
            src={posts.thumbnail.url}
            alt={posts.thumbnail.url}
          />
        </div>
        <br />
        <ReactMarkdown>{posts.body}</ReactMarkdown>
      </div>
    </>
  );
};

export async function getStaticProps({ params: { slug } }) {
  const res = await fetch(
    `https://someapi./blogs?slug=${slug}`
  );
  const blogPost = await res.json();

  return {
    props: {
      posts: blogPost[0],
    },
    revalidate: 600,
  };
}

export async function getStaticPaths() {
  // Get Post From Strapi
  const res = await fetch(
    "https://someapi./blogs"
  );
  const post = await res.json();
  //  Retrun Enrich Content
  return {
    paths: post.map((posts) => ({
      params: { slug: String(posts.slug) },
    })),
    fallback: true,
  };
}

export default Post;
Share Improve this question asked Sep 27, 2021 at 5:24 KotjengOrenKotjengOren 791 silver badge8 bronze badges 2
  • 2 You checked if posts exists here: <title>{posts && posts.title}</title>, but forgot to do it here: <h1>{posts.title}</h1> – Nicholas Tower Commented Sep 27, 2021 at 5:25
  • @NicholasTower Yep Sure, But now the problem is goes to post.dateTime, I mean the conditional did help but shall I do that for all? Is there any more graceful way of solving this? – KotjengOren Commented Sep 27, 2021 at 5:31
Add a ment  | 

3 Answers 3

Reset to default 3

Solution 1 You need to check if attribute exists first with optional chaining :

  <h1>{posts?.title}</h1>

Solution 2 or object is not null return null until data loads

if(!posts) return null

return <div> ...Code </div>

The issue occurs because you're using fallback: true in getStaticPaths, and you're not handling the fallback page which gets served by Next.js before getStaticProps finishes running. At that point the props passed to the page ponent will be empty.

In the “fallback” version of a page:

  • The page’s props will be empty.
  • Using the router, you can detect if the fallback is being rendered, router.isFallback will be true.

— Next.js, Fallback Pages documentation


#1 Handle fallback page with router.isFallback

You can properly handle the fallback version of the page using router.isFallback.

const Post = ({ posts }) => {
    const router = useRouter()

    // Display loading until `getStaticProps()` finishes running, and populates the props.
    if (router.isFallback) {
        return <div>Loading...</div>
    }

    return (
        <h1>{posts.title}</h1>
    );
};

#2 Use fallback: 'blocking' instead

As an alternative, if you don't really need the fallback functionality, you can change the fallback value in getStaticPaths to fallback: 'blocking'. This will still generate new pages like fallback: true, but will wait until getStaticProps has ran before rendering the page.

export async function getStaticPaths() {
    const res = await fetch("https://someapi./blogs");
    const post = await res.json();

    return {
        paths: post.map((posts) => ({
            params: { slug: String(posts.slug) }
        })),
        fallback: 'blocking'
    };
}
    <Head>
        <title>{posts && posts.title}</title>
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0"
        ></meta>
      </Head>
      <div className="container" style={{ marginTop: "3.85rem" }}>
        <div className="row">
          <h1>{posts && posts.title}</h1> // You've just forgot that if posts exist condition
        </div>
        <div className="row d-flex justify-content-end">
          <p style={{ textAlign: "right" }}>
            {moment(posts.dateTime).format("dddd, Do MMMM YYYY, hh:mm:ss a")}
          </p>
        </div>
        <br />
        <div className="row d-flex justify-content-center">
          <img
            className="postThumbNail"
            src={posts.thumbnail.url}
            alt={posts.thumbnail.url}
          />
        </div>
        <br />
        <ReactMarkdown>{posts && posts.body}</ReactMarkdown>
      </div>

本文标签: javascriptTypeError Cannot read property 39title39 of undefined NextJSStack Overflow