A Nice Way to Handle React Server Actions with react-hot-toast

A Nice Way to Handle React Server Actions with react-hot-toast

Posted by

kamlesh paul

on

Dec 20, 2024

4 min read

Last updated on : Dec 20, 2024

282 views

Server actions in React can be tricky to manage, especially when it comes to providing users with feedback on the status of their action. In this article, we’ll explore a clean and user-friendly approach to handling React server actions using react-hot-toast.

Table of contents

Why Use react-hot-toast?

I was using traditional server actions with <form action=""> and struggling to provide good user feedback. Then I discovered this cool method, and I hope you’ll find it helpful too!

react-hot-toast is a lightweight, customizable, and beautiful toast notification library for React. It’s perfect for showing real-time feedback to users during async actions. Using its toast.promise() method, you can manage loading, success, and error states in one neat package.

Example Use Case

Let’s create a simple newsletter subscription form. Users will enter their email and click the Subscribe button. Here’s how we’ll handle it:

  • Show a loading state when the form is submitted.
  • Display a success message if the subscription is successful.
  • Handle errors gracefully with a descriptive error message.

Here’s the complete code implementation.

Step 1: Define a Response Interface

  • Before diving into the implementation, let’s define the structure of our server’s response:
types.d.ts
interface ActionResponse {
  status: 'success' | 'error';
  message: string;
  data?: any;
}

This ensures consistency and clarity when working with server responses.

Step 2: The Frontend - Subscribe Component

  • In the Subscribe component, we’ll use react-hot-toast to handle feedback during the subscription process:
Subscribe.tsx
"use client"
 
const handleSubscribe = () => {
 
  const result = subscribeToNewsletterAction(values);
  
  toast.promise(result, {
    loading: 'Subscribing...',
    success: (data: ActionResponse) => {
      setLoading(false);
      if (data.status === 'success') {
        form.reset();
        return data.message;
      }
      throw new Error(data.message);
    },
    error: (err: any) => err.toString(),
  });
 
}

Here’s what’s happening:

  • Loading: As soon as the user submits the form, they see a “Subscribing…” message.
  • Success: If the server responds with a success status, the form is reset, and a confirmation message is displayed.
  • Error: If there’s an issue, the error message from the server is shown instead.

Step 3: The Backend - Action Handler

  • Now, let’s create the server-side function that processes the subscription:
action.ts
export const subscribeToNewsletterAction = async (payload: z.infer<typeof newsletterSchema>): Promise<ActionResponse> => {
 
  const input = newsletterSchema.parse(payload);
 
  try {
    // subscribe
    return {
      message: 'Thank you for subscribing! You’ll now receive the latest updates straight to your inbox.',
      status: 'success'
    }
 
  } catch (error) {
    return {
      message: 'Oops! Something went wrong while processing your request. Please try again later.',
      status: 'error'
    }
  }
}

Here:

  • We validate the user’s input using Zod.
  • We use ActionResponse return type for typesafe
  • If the subscription is successful, a success message is returned.
  • If there’s an error, an appropriate error message is sent back.

Security Considerations

Server actions are essentially public-facing endpoints. Avoid returning any sensitive data in the response. If necessary, implement proper authentication and authorization checks before executing the code to ensure secure access.

Step 4: Custom Toast Styling

  • You can customize every aspect of your toasts:
toast.promise(result, {
  loading: {
    message: 'Working on it...',
    icon: '⚡️',
    style: {
      background: '#2196F3',
      color: 'white',
    },
  },
  success: {
    message: data => `${data.message} 🎉`,
    duration: 4000,
    icon: '🌟',
  },
  error: {
    message: err => getErrorMessage(err),
    duration: 5000,
    icon: '💫',
  },
});

For further options and details, check out https://react-hot-toast.com/

Conclusion

By combining React Server Actions with react-hot-toast, we've created a robust, user-friendly system for handling asynchronous operations. This approach not only improves the user experience but also makes our code more maintainable and type-safe.

Get updates directly to your inbox.

Join 500+ developers getting updates on Laravel & Next.js tips. No spam,
unsubscribe anytime.


Share this article:

282 views