How to show a toast message when using Server Actions in Next.js

From the moment Server Actions and Server Components came out, there's a common tendency to avoid client code. And for a good reason. We want to harness the server's power and run as little code as possible in the browser to improve our app's performance.

Server vs. Client Components

If you need a better understanding of the difference between Server and Client Components, read Making Sense of React Server Components by Josh Comeau.

In Next.js, by default, all components are Server Components. They are rendered on the server and never re-render. If you need to use react hooks or manage state, mark them with the use client directive. Otherwise, you'll get an error. As a rule, you should only change this when you need to. Remember, we should not avoid using Client Components at all costs.

Toast message example

Let's look at how we can display a toast message when successfully submitting a form using Server Actions. Remember, Server Actions are functions executed on the server.

For this example, we'll use the shadcn/ui toast component. Following the docs, let's generate and add the component to our root layout.

npx shadcn-ui@latest add toast
// app/layout.tsx

import { Toaster } from "@/components/ui/toaster"

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head />
      <body>
        <main>{children}</main>
        <Toaster />
      </body>
    </html>
  )
}

Let's create a form component that adds a new task item.

// app/components/new-task-form.tsx

export function NewTaskForm() {
  async function createTask(formData) {
    'use server'

    // ...
  }

  return (
    <form action={createTask}>
      <input name="title" />
      <button type="submit">Add task</button>
    </form>
  )
}

At this point, our component is a Server Component. We'll mark it with the use client directive so we can call the useToast hook.

// app/components/new-task-form.tsx

'use client'

import { useToast } from '@/components/ui/use-toast';

export function NewTaskForm() {
  async function createTask(formData) {
    'use server'

    // ...
  }

  return (
    <form
      ref={ref}
      action={async (formData) => {
        await createTask(formData);
        toast({ description: 'Task created successfully' })
      }}
    >
      <input name="title" />
      <button type="submit">Add task</button>
    </form>
  )
}

And for the last step, let's use the form component within a page.

// app/new-task/page.tsx

import { NewTaskForm } from '@/components/new-task-form'

export default function NewTask() {
  return <NewTaskForm />;
}

That's it! See how we can use our form component on a page or within another component, regardless of whether it's a Server or a Client component.

Subscribe for more like this!

Drop your email below and I'll send you new stuff to your inbox!

No spam, ever. I respect your email privacy. Unsubscribe anytime.

Read more similar articles