【问题标题】:Getting TypeError on prerendering page in npm run build在 npm run build 的预渲染页面上获取 TypeError
【发布时间】:2021-06-29 01:52:36
【问题描述】:

我正在我的 Next.js 应用程序中预呈现此页面:

const router = useRouter();

if (!router.isFallback && !postData?.slug) {
    return <p>hmm... looks like an error</p>
}

const formatDate = date => {
    const newDate = new Date(date);

    return `${newDate.getDate()}/${
        newDate.getMonth() + 1
    }/${newDate.getFullYear()}`
};


    return (
    <div className={styles.container}>
        <Head>
            <title>{postData.title}</title>
            <link rel='icon' href='/favicon.ico' />
        </Head>

        <main className={styles.main}>
            {router.isFallback ? (
                <h2>Loading...</h2>
            ) : (
                <article className={blogStyles.article}>
                    <div className={blogStyles.postmeta}>
                        <h1 className={styles.title}>{postData.title}</h1>
                        <p>{formatDate(postData.date)}</p>
                        <img src={postData.featuredImage.node.sourceUrl} />
                    </div>
                    <div
                        className='post-content content'
                        dangerouslySetInnerHTML={{ __html: postData.content }}
                    />
                </article>
            )}
            <p>
                <Link href={`/blog`}>
                    <a>Back</a>
                </Link>
            </p>
        </main>
    </div>
)

使用getStaticProps()

    export async function getStaticProps({ params }) {
    const data = await getPost(params.slug);

    return {
      props: {
        postData: data.post
      }
    };
  }

使用getStaticPaths()

export async function getStaticPaths() {
    const allPosts = await getAllPostsWithSlug();

    if (
        allPosts &&
        allPosts.edges !== null &&
        allPosts.edges.node !== null &&
        allPosts.edges.length > 0
    ) {
        return {
            paths: allPosts.edges.map(({ node }) => `/blog/${node.slug}`) || [],
            fallback: true
        }
    }

}

当我在本地运行它时,它工作正常,但是当我尝试使用 npm run build 部署它时,它仅针对 title 属性给出错误:

Error occurred prerendering page "/blog/[slug]". Read more: https://err.sh/next.js/prerender-error
TypeError: Cannot read property 'title' of undefined

这是让我感到困惑的部分,因为我不明白为什么错误只出现在查询的 1 个属性 (postData.title) 上,而其他一切都正常加载。

我正在使用 GraphQL 创建查询:

export async function getPost(slug) {
    const data = await fetchAPI(
      `
      fragment PostFields on Post {
        title
        excerpt
        slug
        date
        featuredImage {
          node {
            sourceUrl
          }
        }
      }
      query PostBySlug($id: ID!, $idType: PostIdType!) {
        post(id: $id, idType: $idType) {
          ...PostFields
          content
        }
      }
    `,
      {
        variables: {
          id: slug,
          idType: 'SLUG'
        }
      }
    );

    return data;
}

我通过一个 api.js 文件导入这个函数,并使用 getStaticProps() 函数中的数据。

对此的任何帮助将不胜感激,我在网上寻找解决方案,但找不到任何有效的解决方案。谢谢!

【问题讨论】:

  • 你能显示整个page.js吗?类似于function home ({postData}){}
  • 它只会在postData.title 出错,因为这是您尝试从该页面中的postData 访问的第一个属性,出错后它不会到达其他属性。

标签: javascript reactjs graphql next.js server-side-rendering


【解决方案1】:

如果有人使用yarn export 遇到此问题或类似问题,解决方案是将回退设置为 false。这为我修复了所有页面呈现错误。

来自 Next.js 文档:

// This function gets called at build time
export async function getStaticPaths() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // We'll pre-render only these paths at build time.
  // { fallback: false } means other routes should 404.
  return { paths, fallback: false }
}

【讨论】:

    【解决方案2】:

    在处理动态页面时,例如 /blog/[slug].jsx,除了上面返回的 jsx 中使用的 getStaticPropsrouter.isFallback? 之外,您还需要使用 getStaticPaths

    getStaticPaths catches incoming possible paths -- 然而,它的行为取决于fallback 键(其值可以是truefalse"blocking"

    Blocking 与服务器端渲染相同,因此它会根据需要为getStaticPaths 未返回的路径生成静态 HTML。这将被缓存以供将来使用,因此这种按需生成仅在您的getStaticPaths 函数未处理的每个路径中发生一次。如果您将getStaticPaths 设置为true,则将在构建时呈现一小部分动态路径,并且如果在初始构建期间未呈现用户导航到的路径,则会向用户显示加载指示器。使用true 对于大型电子商务站点或具有大量动态路径的站点很有用,这样构建过程就不会花费很长的时间来完成。将getStaticPaths 设置为false 将导致在构建过程中未呈现任何路径,如果用户导航到它,则会导致404 错误。根据您的需要,上述任何方法都可能是最合适的。也就是说,重要的是要注意"blocking" 根本不需要使用router.isFallback。我还建议研究使用 revalidategetStaticProps 的好处。

    以下是使用getStaticPaths 捕获传入动态路径的示例:

    const AboutSlugsQueryVars: AboutSlugsVariables = {
        order: OrderEnum.ASC,
        field: PostObjectsConnectionOrderbyEnum.SLUG,
        first: 15
    };
    
    type DynamicPaths = {
        params:
            | {
                    slug: string | Array<string>;
              }
            | never[];
    }[];
    
    export async function getStaticPaths(
        ctx: GetStaticPathsContext,
        pathsData: DynamicPaths
    ) {
        const q = ctx!.defaultLocale;
        console.log(`${q}`)
        const apolloClient = initializeApollo();
        const { data } = await apolloClient.query<AboutSlugs, AboutSlugsVariables>({
            query: ABOUT_SLUGS,
            variables: AboutSlugsQueryVars
        });
    
        pathsData = [];
    
        if (
            data &&
            data.aboutslugs !== null &&
            data.aboutslugs.edges !== null &&
            data.aboutslugs.edges.length > 0
        )
            data.aboutslugs.edges.map(post => {
                if (post !== null && post.node !== null && post.node.slug !== null) {
                    pathsData.push({ params: { slug: post.node.slug } });
                }
            });
    
        return {
            paths: pathsData,
            fallback: true
        };
    }
    
    

    过滤getStaticPaths的方法有很多,你也可以使用GetStaticPathsContext来捕获传入的locales以及默认的locale(如果适用)。

    【讨论】:

    • 我已经使用了 fallback 和 getStaticPaths()。我应该附上代码。我更新了我的问题。这仅适用于我遇到此错误的领域之一,这让我感到困惑。感谢您的回复!
    猜你喜欢
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 2022-12-21
    • 2021-03-03
    • 1970-01-01
    • 2022-09-23
    相关资源
    最近更新 更多