Tips for incorporating a single database or API call into both the `generateMetadata` and `Page` components within a Next.js App Router

Currently, I am developing a project in NextJs 14 and utilizing the App Router. In my server component app/blogs/[slug]/page.tsx, I have written the following code:

import { Metadata } from "next";

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

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

  // First database query
  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 database query. A bit redundant to call twice 😥
  const blog = await prisma.blog.findFirst({
    where: { slug },
  });

  ...

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

export default BlogDetailPage;

The issue at hand is that I need to make two separate queries to the database to fetch data for the dynamic metadata (generateMetadata) and the dynamic component (BlogDetailPage). This approach seems inefficient as it involves repeating the same query.

I am wondering if there is a way in NextJs to optimize this process by fetching the blog data from the database only once and then using it in both the generateMetadata function and the BlogDetailPage component?

Answer №1

Suggested Solution :

Consider utilizing React Cache to optimize your DB call function cache

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

// YOUR DB CALL

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

Update from :

const blogInfo = await prisma.blog.findFirst({ where: { slug }, });

to

const blogInfo = await FetchBlogByID()

Visualize how the code changes :

import { cache } from 'react';

const FetchBlogData = cache(async () => {

// YOUR DB CALL

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


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

  // Initial DB call
  const blogInfo = await FetchBlogData()
  
  return {
    title: `${blogInfo?.title} | Blog - MyWebsite`,
    description: blogInfo?.subtitle,
  }
}


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

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

  const blogInfo = await FetchBlogData()
  ...

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

export default BlogDetailPage;

Please Refer to :

  1. React Cache : https://react.dev/reference/react/cache

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Learning to implement $first in an Angular ng-repeat to dynamically add a new table row

I am currently facing an issue with displaying a Google map for addresses in my Angular application. The problem seems to be related to the asynchronous nature of HTML and JS, but I am struggling to find a solution. The issue is that even though the map vi ...

Can the inclusion of additional parameters compromise the type safety in TypeScript?

For demonstration purposes, let's consider this example: (playground) type F0 = (x?: string) => void type F1 = () => void type F2 = (x: number) => void const f0: F0 = (x) => console.log(x, typeof(x)) const f1: F1 = f0 const f2: F2 = f1 f ...

Image not appearing when sharing on Facebook

I've been trying to create a Facebook share button using the Javascript SDK, and here is the code I have been utilizing: $(function() { $('.facebook-share').click(function(e) { e.preventDefault(); FB.ui({ method: 'feed& ...

Troubleshooting a dysfunctional Vue.js component

I am currently facing a challenge in getting components to function properly. Interestingly, without the component, everything seems to be working fine (as per the commented code). Here is my HTML snippet: <strong>Total Price:</strong> <sp ...

Encountering a CORS issue when utilizing Stripe with various servers while navigating with a Router

I have a router that utilizes Router.express(). The backend operates on port 5000, while the frontend runs on port 3000. Within the frontend folder, there is a button with a fetch request (http://localhost:5000/create-checkout-session). In the backend, the ...

Alert: Potential shared module issue detected when updating swr from version 1 to version 2 within a NextJS application

I have decided to upgrade my swr package from version 1 to the latest version 2. Here is a glimpse of my package.json. I am currently utilizing React 18, NextJS 12, and Webpack 5 for this project, including the ModuleFederationPlugin integration. { " ...

Whenever I try to execute the command `electron .` in the electron-quickstart project, I immediately encounter an error within the

Upon successfully installing Electron, I attempted to run it using "electron" or "electron -v" commands. Unfortunately, I encountered an error while running it on Windows 10. C:\Windows\System32\electron-quick-start>electron -v modu ...

The three.js animation fails to load on Github Pages

I have encountered an issue with my website. It runs smoothly when I use "parcel index.html" locally, but once I post it to Github pages, the JavaScript animation does not display. Upon checking the browser console, I see no errors. Can anyone provide guid ...

How to iterate through an array in jQuery/JavaScript and create variables in each loop?

I've been puzzled for a while now as to why this code snippet doesn't work as intended: if (longest.length >= 3) { for ( var i = 0; i < longest.length-1; i++) { var $last[i] = longest[i].splice(-1).toString(); //if ( $( $la ...

Issue with AddToAny plugin not functioning properly on FireFox

I’m having issues with AddToAny for social media sharing on my website. It seems like FireFox is blocking it because of tracking prevention measures. Error Message in Console: The resource at “https://static.addtoany.com/menu/page.js” was blocked d ...

Maintaining checkbox state using fetch arrays

Included below is the code present on my site, pulling data for each season including numbers of home wins, win percentage, and win lsp. It functions correctly by creating a new table row for each season. Furthermore, there are two columns featuring filte ...

Utilize the browser console to interact with AngularJS components such as scope or directives

What is the method for accessing Angularjs elements in a web browser? $scope, Controller, Directive, $scope.function ...

Comparing TypeScript's `return;` with `return undefined;`: which is better?

I encountered a strange behavior that is puzzling to me, and I'm not sure if there's a logical explanation for it. In TypeScript, the following code works perfectly: type UndefinedFunction = () => undefined; let uf: UndefinedFunction = funct ...

Drag-and-drop functionality in Angular JavaScript Tree View for rearranging nodes and inserting new nodes

Exploring the world of JavaScript Tree Views and Angular as a beginner. After scouring the internet for information, I'm struggling to find a solution to my specific query. Looking for a tree-view component that seamlessly integrates with Angular, c ...

An error of `SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data` is occurring in relation to Django Channels

Whenever I attempt to access a JSON array object sent by the consumer (channels), I encounter the following error message: "SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data" async def websocket_connect(self,event): pri ...

Setting an optional property to null is not permitted

In my model class, I have defined an optional property as follows: export class Workflow { constructor( public id: number, public started: Date, public documentId: number, public document: Document, public status: WorkflowStatus, ...

Utilize PHP in an APP Engine Application to send an email to a Gmail address

I have a project deployed on Google App Engine where I need to send an email once a user submits the contact form. My app is successfully deployed and I have implemented an ajax request to a PHP file, but unfortunately, it's not functioning as expect ...

Getting the length of child elements in Angular using ngFor loop

Can anyone help me figure out how to check the length of a child element in my Angular *ngFor loop? I am fetching data from a real-time firebase database. What am I doing wrong? Here is the code snippet I am using: <div *ngFor="let event of events"> ...

Enhance the HTML content using a JavaScript function

Here is the code that I have: <label>Brand</label></br> <select name="brand" id="brand" onChange="changecat(this.value);"> <option value="" selected>Select Brand</option> <option value="A">AMD</option&g ...

"Encountering a 404 error while trying to deploy a Next.js application using

I am currently in the process of deploying a Next.js app on GitHub Pages using GitHub Actions. However, even after successful deployment, I am encountering a 404 error on the page. I have searched through multiple similar questions, but I am struggling to ...