- Website
- Sabin Hertanu
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.