How to call a notification/toast after a server action in Nextjs13 – Javascript

by
Ali Hasan
ecmascript-6 next.js next.js13 reactjs

Quick Fix: You can set a cookie on the server action and read it on the next request, when the user is being redirected back to the page. You could set the cookie with a short expire time. You could put whatever you want in the cookie and render your toast based on it.

The Problem:

In Next.js 13, server actions allow for data manipulation on the server-side. However, displaying a toast notification after a successful server action requires coordination between the server and client, as toasts are typically rendered on the client.

The Solutions:

Solution 1: Option 1

Set a cookie on the server action and read it on the next request.
Cookies can be set with a short expire time and store necessary data that can be used to render toast notifications.

// Server action file
import { cookies } from "next/headers";

// At the end of your server action function:
cookies()
  .set(
    "my-app-toast-msg",
    JSON.stringify({ error: true, msg: "wrong credentials" }, {
      expires: new Date(Date.now() + 10 * 1000), // 10 seconds
    })
  );
// At your server component file
import { cookies } from "next/headers";

export async function Page() {
  const toastMsg = cookies().get("my-app-toast-msg");

  return (
    <>
      {!!toastMsg &&
        JSON.parse(toastMsg).error &&
        <ClientErrorToast errorMsg={JSON.parse(toastMsg).msg} />}
      ...
    </>
  );
}

Solution 2: Using `useFormStatus()` hook

The `useFormStatus()` hook can be utilized to manage the data returned by the server action and display errors or success messages accordingly. This hook takes the server action and an initial state as parameters. In the provided example, the server action returns an object with error and message properties.

A useEffect() hook can be used to observe changes in the state and trigger a toast. In this case, the toaster from shadcn is used to display a toast with the title "Error" or "Success" depending on the state, and the description is set to the message returned from the server action.

Solution 3: Using a Custom Flash Toaster Library

To resolve the issue of triggering toasts after server actions in Next.js 13, a custom library named "flash-toaster" is introduced. This library handles the persistence of messages across redirects and provides a convenient interface for displaying notifications.

Implementation:

  • Create a new file named lib/flash-toaster/flash-toaster.tsx with the following code:
import { Toaster } from '@components/ui/sonner';
import FlashToasterClient from './flash-toaster-client';
import { cookies } from 'next/headers';

export function FlashToaster() {
  const flash = cookies().get('flash');
  return (
    <>
      <Toaster />
      <FlashToasterClient flash={flash?.value} />
    </>
  );
}

export function setFlash(flash: { type: 'success' | 'error'; message: string }) {
  cookies().set('flash', JSON.stringify(flash), { path: '/', expires: new Date(Date.now() + 10 * 1000) });
}
  • Create a new file named lib/flash-toaster/flash-toaster-client.tsx:
use client;
import { useEffect } from 'react';
import { toast } from 'sonner';

export default function FlashToasterClient(props: { flash: string | undefined }) {
  useEffect(() => {
    if (!!props.flash) {
      const { type, message } = JSON.parse(props.flash);
      if (type === 'success') {
        toast.success(message);
      } else if (type === 'error') {
        toast.error(message);
      }
    }
  }, [props.flash]);
  return null;
}
  • Create a new file named index.ts in the lib/flash-toaster directory:
import { FlashToaster, setFlash } from './flash-toaster';
export { FlashToaster, setFlash };
  • In your layout component, where you typically place the Toaster component, replace it with the FlashToaster component:
import { FlashToaster } from '@lib/flash-toaster';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head />
      <body>
        <main>{children}</main>
        <FlashToaster />
      </body>
    </html>
  );
}
  • Within your action function, you can set a flash message that will persist across redirects using the setFlash function:
export function createUser() {
  ... create the user ...

  setFlash({ type: 'success', message: 'User created successfully' });
  redirect(`/users`);
}

Q&A

Can I call toast notification after a server action in Nextjs13 ?

There is no direct way to do this but you can achieve it using workarounds using cookies or global state

How use useFormStatus() hook to achieve this ?

you can use useFormStatus() hook to manage data returned by server action and display errors adjacent to each input and trigger a toaster by setting a useEffect that observes the state.

What is your custom solution using library ?

You can use flash-toaster library, a small library that works with nextjs and shadcn to handle this.

Video Explanation:

The following video, titled "Build and Deploy a Full Stack Realtime Chat Messaging App with ...", provides additional insights and in-depth exploration related to the topics discussed in this post.

Play video

In this video, we'll build a full stack realtime chat app with NextJS 13 together. We'll be using Upstash Redis as our database, ...