emilkowalski / sonner

An opinionated toast component for React.

Home Page:https://sonner.emilkowal.ski

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Rendering message on React Server Component page load

ScreamZ opened this issue · comments

I would like your insight on a use case,

I'm using NextJS with RSC and I would like to display a message to a user arriving on the website only if it is logged.

Currently I ended up with this pattern, but sadly I have to render null, is there any way to proceed ? I used such pattern when hooks where not existing, but now we are supposed to use hooks, but using a custom hook with use client doesn't seems to work.

"use client";
import { Session } from "next-auth";
import { useEffect, useRef } from "react";
import { toast } from "sonner";

type HelloBannerProps = {
  session: Session | null;
};

export function HelloBanner({ session }: HelloBannerProps) {
  const isHandled = useRef(false);

  useEffect(() => {
    const userName = session?.user?.name;

    if (userName && !isHandled.current) {
      isHandled.current = true;
      requestAnimationFrame(() => toast(`Welcome back to the ${userName}!`));
    }
  }, [session]);

  return null;
}

Thanks

EDIT:

Humm, it seems complicated with server components when the URL change useEffect is played again. Not sure how to deal with my use case now

I guess this is a use case for a full client mode? But how? Was easier with page router 😅

Screen.Recording.2024-05-01.at.18.52.02.mov

Hi @ScreamZ,
You can extract out the part the needs to rendered on the client side only to a separate component and import the component into the server component using a dynamic import.

Example: (Javascript)

// ServerComponent.js 

// Importing the component using 'next/dynamic' so that its only be rendered on the client side, not server side.
const ClientComponet = dynamic(() => import("./ClientComponent.js"), {
  ssr: false // When setting the SSR flag to false, the component is not pre-rendered on the server.
})

export default function ServerComponent() {
  return (
    // Application code.
   <ClientComponent />
  )
}

For more details you can read the official docs on the NextJs Website (next/dynamic)

Yes thanks, but doing this way I still need to render an empty component, i cannot just use an hook isn't ?

I am also creating a toast library (toast-ease@v0.0.1), you can have a look at that, though its still under development. (https://github.com/gurvirsinghbaraich/toast-ease)

@ScreamZ Hi, I also published the package to npm registry (https://www.npmjs.com/package/toast-ease). The project is still at v0.0.1. The package supports rendering a toast from client side and server side.

Video Demo

demo.mov

Code

// Layout.tsx
import { ToastBox } from "toast-ease";
import { ServerToastRegister } from "toast-ease/server";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={spaceGrotesk.className}>
        <ServerToastRegister />
        <ToastBox duration={3} toastsVisible={5} />
        <main>{children}</main>
      </body>
    </html>
  );
}

Rendering a toast from server is this simple

// page.tsx

import { toast } from "toast-ease/server";

export default async function Homepage() {
  toast({
    // An env variable that is only available on the server
    title: process.env.SERVER_SECRET,
  });

  return (
    null
  );
}