Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a way to get data on Head and Page from a single database query #44595

Closed
Josehower opened this issue Jan 5, 2023 · 4 comments
Closed

Comments

@Josehower
Copy link
Contributor

Josehower commented Jan 5, 2023

Describe the feature you'd like to request

To start, I want to thank you for the awesome work. I have been enjoying Next.js 13 a lot and all these amazing features that you bring to us.

Experimenting with the new app directory architecture, I found it very hard to get the same data in Head.jsx and Page.jsx from a single query from the database.

In the following example, I am trying to get the title of the page for the Head, and using this title as h1 as well.

Right now, this is going to result in two different database queries:

Two separate queries to the Database

// head.jsx
import { getPageInfoFromDatabase } from '../database/index';

export default async function Head() {
  // Database query No. 1
  const pageInfo = await getPageInfoFromDatabase();

  return (
    <>
      <title>{pageInfo.title}</title>
      <meta name="description" content={pageInfo.description} />
      <link rel="icon" href="/favicon.ico" />
    </>
  );
}
// page.jsx
import { getPageInfoFromDatabase } from '../database/index';

export default async function Home() {
  // Database query No. 2
  const pageInfo = await getPageInfoFromDatabase();

  return (
    <main>
        <h1>{pageInfo.title}</h1>
        <p>{pageInfo.data} </p>
    </main>
  );
}

I also created a reproduction example that presents query data directly from the page. In the example, it can be tested how the direct call approach results in multiple function call.

https://github.com/Josehower/next-13-data-fetching-demo

Describe the solution you'd like

A possible solution would be either:

  1. A way to communicate between Head, Layout, and Page components so that I can perform a single query to get data on all of them without using an API. Similar to how you can pass props from _app.js to the page components

A possible API for this communication may be this:

// layout.jsx
import { getPageInfoFromDatabase } from '../database/index';

export default async function RootLayout({ Head, Page }) {
  const pageInfo = await getPageInfoFromDatabase();
  return (
    <html lang="en">
      <Head pageInfo={pageInfo} />
      <body>
        <Page pageInfo={pageInfo} />
      </body>
    </html>
  );
} 
  1. Next.js using a similar approach to fetch() Deduping for direct database/function calls

Describe alternatives you've considered

I am aware that Next.js perform a fetch deduping when Head and Page perform a fetch to the same URL (API routes for example). This theoretically would solve my issue but will add some unnecessary HTTP request overhead.

@Josehower
Copy link
Contributor Author

Josehower commented Jan 5, 2023

The following example would create a single query, but it is not what I would like to have since it adds an HTTP request that I think is unnecessary.

Single query to the Database but adds unnecesary HTTP request overhead

// head.jsx

export default async function Head() {
  const request = await fetch('http://localhost:3000/api/pageInfo');
  const pageInfo = await request.json();


  return (
    <>
      <title>{pageInfo.title}</title>
      <meta name="description" content={pageInfo.description} />
      <link rel="icon" href="/favicon.ico" />
    </>
  );
}
// page.jsx

export default async function Home() {
  const request = await fetch('http://localhost:3000/api/pageInfo');
  const pageInfo = await request.json();

  return (
    <main>
        <h1>{pageInfo.title}</h1>
        <p>{pageInfo.data} </p>
    </main>
  );
}
// pages/api/pageInfo.js
import { getPageInfoFromDatabase } from '../../database';

export default async function handler(req, res) {
  const pageInfo = await getPageInfoFromDatabase();
  res.status(200).json(pageInfo);
}

@Josehower Josehower changed the title Currently there is no way to get data on Head and Page from in a single query Implement a way to get data on Head and Page from in a single database query Jan 5, 2023
@Josehower Josehower changed the title Implement a way to get data on Head and Page from in a single database query Implement a way to get data on Head and Page from a single database query Jan 5, 2023
@karlhorky
Copy link
Contributor

karlhorky commented Jan 5, 2023

This looks like a cool proposal! 🙌 The passing of props from Layout to Head and Page would be useful for a lot of things.

Also feels like the Component prop in pages/_app.tsx:

export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

https://nextjs.org/docs/advanced-features/custom-app

@karlhorky
Copy link
Contributor

karlhorky commented Jan 5, 2023

@sebmarkbage @leerob @timneutkens if these proposals above are not tenable and Vercel has no plans on creating these features, are there any alternative plans on offering some new APIs like react-pg, react-fs, etc as mentioned here:

Remove old react-fetch, react-fs and react-pg libraries

...we announced that we're moving away from [them] in favor of reactjs/rfcs#229.

We might explore using these package for other instrumentation in the future but not now and not like this.

@sebmarkbage
Copy link
Contributor

You can use cache from react to create a function that's deduped.

import {cache} from "react";

const getPageInfoFromDatabase = cache(function getPageInfoFromDatabase() {

});

@vercel vercel locked and limited conversation to collaborators Jan 6, 2023
@balazsorban44 balazsorban44 converted this issue into discussion #44639 Jan 6, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants