firebase / friendlyeats-web

Apache License 2.0
463 stars 409 forks source link

RootLayout - how to provide currentUser to entire app while maintaining RootLayout as a server component #305

Open jamezening opened 1 month ago

jamezening commented 1 month ago

Currently in the RootLayout, the currentUser is only provided to the <Header> component.

Is there a way to "provide" the currentUser to the entire app (including <main> and its children), without making the RootLayout into a client component so that user related state is available not just in Header ?

export default async function RootLayout({ children }) {
  const { currentUser } = await getAuthenticatedAppForUser();
  return (
    <html lang="en">

      <body>
            <Header initialUser={currentUser?.toJSON()}/>

        <main>{children}</main>
      </body>

    </html>
  );
}

There are other Firebase + NextJS examples out there that wrap the entire <main> tag in a React Context Provider - still figuring out if it is performant to make the RootLayout into a client component.

Thank you for any insights on this matter.

pashpashpash commented 1 month ago

@jamezening can you try something like this:

import React from 'react';

export default async function RootLayout({ children }) {
    const { currentUser } = await getAuthenticatedAppForUser();

    return (
        <html lang="en">
            <body className="">
                <Header initialUser={currentUser?.toJSON()} />

                <main>
                    {React.Children.map(children, child =>
                        React.cloneElement(child, { currentUser })
                    )}
                </main>
            </body>
        </html>
    );
}
adrolc commented 1 month ago

@jamezening There is a useUser hook in src/lib/getUser.js. You can also create a context and put this state there

jamezening commented 1 month ago

@jamezening can you try something like this:

import React from 'react';

export default async function RootLayout({ children }) {
    const { currentUser } = await getAuthenticatedAppForUser();

    return (
        <html lang="en">
            <body className="">
                <Header initialUser={currentUser?.toJSON()} />

                <main>
                    {React.Children.map(children, child =>
                        React.cloneElement(child, { currentUser })
                    )}
                </main>
            </body>
        </html>
    );
}

@pashpashpash thank you for the suggestion. Either GH Co-Pilot or Cursor AI suggested this method for me but I couldn't get it to work.

Did this method end up working for you?

jamezening commented 1 month ago

@jamezening There is a useUser hook in src/lib/getUser.js. You can also create a context and put this state there

@adrolc I ended up going this way, while moving the onAuthStateChanged logic out of the Header component into a "Side Effect Component" component (not my favorite pattern, but haven't come up with a better way)