Next.js Discord

Discord Forum

Correct way of consuming TRPC NextAuth context with 'use client' useRouter

Answered
Prairie yellowjacket posted this in #help-forum
Open in Discord
Avatar
Prairie yellowjacketOP
Hi, I have made a header component /_comp.../Header.tsx that has pathname route logic this requires 'use client' however, I have a sign in function that consume the TRPC context via next auth getServerAuthSession(), due to the 'use client' we now get.
Error: ❌ Attempted to access a server-side environment variable on the client
partly due to the prisma server tring to validate the user logic
what's the best way around this, client/server logic?
Answered by Ray
1. you should use metadata api for the header in app router instead of next/head
2 we can render the server component with the children props in client component
View full answer

20 Replies

Avatar
Ray
turn the sign in function to server action so we can handle it on server side
Avatar
Prairie yellowjacketOP
so break out the header function ?
header.tsx
'use client'

import signinhelper.tsx
-consume rout logic
-consume signinhelper


signinhelper.tsx
'use server'
-consume getServerAuthSession()
Avatar
Ray
header.tsx
'use client'

import signinhelper.tsx
-consume rout logic
-consume signinhelper


signinhelper.tsx
'use server'
-consume signin()
Avatar
Prairie yellowjacketOP
hmm, a bug? so we have some psuedo 'use client' ('use server' (async getServerAuthSession())

1 of 1 unhandled error
Next.js is up to date

Unhandled Runtime Error
Error: async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding `'use client'` to a module that was originally written for the server.
Avatar
Ray
could you show the code
Avatar
Prairie yellowjacketOP
sure
src/app/page.tsx
import type { NextPage } from "next";
import Head from "next/head";
import { unstable_noStore as noStore } from "next/cache";
import Header from "./_components/Header";


const Home: NextPage = async () => {
  noStore();
  return (
    <>
      <Head>
        <title>Create T3 App</title>
        <meta name="description" content="Generated by create-t3-app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <div className="flex min-h-screen flex-col  text-black">
        <Header />
      </div>
    </>
  );
};

export default Home;
_components/Header.tsx
'use client'
import React from "react";
import Link from "next/link";
import { usePathname } from 'next/navigation'
import SignInHelper from "./signinhelper";

const links = [
  { href: "/jobs", label: "Job Seekers" },
  { href: "/jobs/create", label: "Post a Job" },
  { href: "#", label: "About Us" },
  { href: "#", label: "Contact" },
  { href: "conference", label: "Conferences" },
];

export default function Header() {
    const pathname = usePathname()
 

  return (
    <header className="mx-4 flex h-16 items-center bg-[#ffffff] px-4  md:mx-8 lg:mx-16 lg:px-6">
      <Link className="flex items-center justify-center" href="/">
        <span className="ml-2 text-lg font-bold">MatchPoint</span>
      </Link>
      <nav className="ml-auto flex items-center gap-4 sm:gap-6">
        {links.map((link, index) => (
          <Link
            key={index}
            className={`text-sm font-medium underline-offset-4 hover:underline ${pathname === link.href ? "text-gray-500" : ""}`}
            href={link.href}
          >
            {link.label}
          </Link>
        ))}
        <SignInHelper />
      </nav>
    </header>
  );
};
src/app/_components/signinhelper.tsx
'use server'
import React from "react";
import Link from "next/link";

import { getServerAuthSession } from "~/server/auth";

export default async function SignInHelper() {
    const session = await getServerAuthSession();
  
    return (
      <>
        <Link href={session ? "/api/auth/signout" : "/api/auth/signin"}>
          <div className="rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20">
            {session ? "Sign out" : "Sign in"}
          </div>
        </Link>
      </>
    );
  }
  
this is project from
pnpm create t3-app@latest from
https://github.com/t3-oss/create-t3-app
Avatar
Ray
ok a few problem here
import {type Metadata} from 'next'
import { unstable_noStore as noStore } from "next/cache";
import Header from "./_components/Header";

export const metadata: Metadata = {
    title: 'Create T3 App',
    description: 'Generated by create-t3-app'
}

const Home = async () => {
  noStore();
  return (
    <>
      <div className="flex min-h-screen flex-col  text-black">
        <Header>
            <SignInHelper />
        </Header>
      </div>
    </>
  );
};

export default Home;


'use client'
import React from "react";
import Link from "next/link";
import { usePathname } from 'next/navigation'

const links = [
  { href: "/jobs", label: "Job Seekers" },
  { href: "/jobs/create", label: "Post a Job" },
  { href: "#", label: "About Us" },
  { href: "#", label: "Contact" },
  { href: "conference", label: "Conferences" },
];

export default function Header({children}) {
    const pathname = usePathname()
 

  return (
    <header className="mx-4 flex h-16 items-center bg-[#ffffff] px-4  md:mx-8 lg:mx-16 lg:px-6">
      <Link className="flex items-center justify-center" href="/">
        <span className="ml-2 text-lg font-bold">MatchPoint</span>
      </Link>
      <nav className="ml-auto flex items-center gap-4 sm:gap-6">
        {links.map((link, index) => (
          <Link
            key={index}
            className={`text-sm font-medium underline-offset-4 hover:underline ${pathname === link.href ? "text-gray-500" : ""}`}
            href={link.href}
          >
            {link.label}
          </Link>
        ))}
        {children}
      </nav>
    </header>
  );
};


import Link from "next/link";

import { getServerAuthSession } from "~/server/auth";

export default async function SignInHelper() {
    const session = await getServerAuthSession();
  
    return (
      <>
        <Link href={session ? "/api/auth/signout" : "/api/auth/signin"}>
          <div className="rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20">
            {session ? "Sign out" : "Sign in"}
          </div>
        </Link>
      </>
    );
  } 
Avatar
Ray
1. you should use metadata api for the header in app router instead of next/head
2 we can render the server component with the children props in client component
Answer
Avatar
Prairie yellowjacketOP
ok so you have brought the signinhelper 'use server' above the 'use client' and set it as a child. will give this a go
Avatar
Ray
you don't need server action in this case, I thought you had a sign in function for it
Avatar
Prairie yellowjacketOP
yes, this has worked. (I had to drop some of the default s for the functions as it was giving some undefined erorr)
for others that tread this path
see working example here
https://github.com/SkippyHub/nextauth-nextrouting-client-server
Thanks Ray.

we might have found a bug about using the server actions.
as in psuedo 'use client' ('use server' (async server action())
Avatar
Ray
no it is not bug, we can't turn a client component to server component with 'use server'
Avatar
Prairie yellowjacketOP
okay, thanks for help and clearign that up
Avatar
Ray
your welcome