如何实现来自数据库或 API 的单个调用以用于 Next.js App Router 中的 `generateMetadata` 和 `Page` 组件

问题描述 投票:0回答:1

目前我正在开发 NextJs 14 并使用 App Router。我有一个服务器组件

app/blogs/[slug]/page.tsx
,其中包含如下代码:

import { Metadata } from "next";

type GenerateMetadataProps = {
  params: { slug: string };
};

export async function generateMetadata({ params }: GenerateMetadataProps): Promise<Metadata> {

  // First call to DB
  const blog = await prisma.blog.findFirst({
    where: { slug: params.slug },
  });
  
  return {
    title: `${blog?.title} | Blog - MyWebsite`,
    description: blog?.subtitle,
  }
}

type BlogDetailPageProps = {
  params: { slug: string };
  searchParams?: { [key: string]: string | string[] | undefined };
}

const BlogDetailPage = async ({ params, searchParams }: BlogDetailPageProps) => {
  const { slug } = params;
  
  // Second call to DB. Kinda working twice for a thing 😥
  const blog = await prisma.blog.findFirst({
    where: { slug },
  });

  ...

  return (
    <>
      ...
    </>
  );
};

export default BlogDetailPage;

问题是我必须向数据库查询两次才能实现动态元数据(

generateMetadata
)和动态组件(
BlogDetailPage
)。调用同一件事两次有点低效。

NextJs 是否可以仅从数据库查询博客一次,但同时利用

generateMetadata
函数和
BlogDetailPage
组件中的数据?

javascript typescript next.js metadata next.js13
1个回答
0
投票

可能的解决方案:

将数据库调用函数包装在 React Cache 中

cache

import { cache } from 'react';
const GetBlogByID = cache(async () => {

// YOUR DB CALL

    const blog = await prisma.blog.findFirst({
    where: { slug: params.slug },
  });
  
  return {
    title: `${blog?.title} | Blog - MyWebsite`,
    description: blog?.subtitle,
  }
})

更换

const blog =等待 prisma.blog.findFirst({ 其中:{ slug }, });

const blog = 等待 GetBlogByID()

您的代码如下:

import { cache } from 'react';

const GetBlogByID = cache(async () => {

// YOUR DB CALL

    const blog = await prisma.blog.findFirst({
    where: { slug: params.slug },
  });
  
  return {
    title: `${blog?.title} | Blog - MyWebsite`,
    description: blog?.subtitle,
  }
})


export async function generateMetadata({ params }: GenerateMetadataProps): Promise<Metadata> {

  // First call to DB
  const blog = await GetBlogByID()
  
  return {
    title: `${blog?.title} | Blog - MyWebsite`,
    description: blog?.subtitle,
  }
}


type BlogDetailPageProps = {
  params: { slug: string };
  searchParams?: { [key: string]: string | string[] | undefined };
}

const BlogDetailPage = async ({ params, searchParams }: BlogDetailPageProps) => {

  const blog = await GetBlogByID()
  ...

  return (
    <>
      ...
    </>
  );
};

export default BlogDetailPage;

请阅读:

  1. 缓存https://react.dev/reference/react/cache

如果您有任何疑问,请发表评论(如果有必要我会更新答案)

© www.soinside.com 2019 - 2024. All rights reserved.