DEV Community

Rafał Goławski
Rafał Goławski

Posted on

🍞 React Router v7: The Problem with Toasts After Form Submissions

Recently, I was working on a React Router v7 application where I needed to display a toast notification after a (un)successful form submission. Naturally, I used an action to return the submission status and utilized it inside a useEffect to trigger the toast. Here's what my initial code looked like:

export async function action() {
  const response = await createPost("Lorem ipsum");
  if (!response.success) {
    return { status: "failed", data: null };
  }
  return { status: "success", data: response.data };
}

export default function MyRoute({ actionData }: Route.ComponentProps) {
  useEffect(() => {
    let description = '';
    if (actionData?.status === "success") {
      description = "Post created successfully 🎉";
    } else if (actionData?.status === "failed") {
      description = "Failed to create post 😵‍💫";
    }
    if (description.length > 0) {
      toast({ description, duration: 2000 })
    }
  }, [actionData?.status]);
  // ...
}
Enter fullscreen mode Exit fullscreen mode

At first glance, this code seems fine. The toast displays correctly after submitting the form, whether the submission succeeds or fails. However, there’s one subtle issue with this approach. Did you spot it already?

The Problem

The problem appears when you submit the form again, and the actionData?.status remains unchanged (e.g., it stays "success" or "failed"). Since the value of actionData?.status hasn’t changed, the useEffect hook won’t re-run, and as a result, the toast notification won’t be displayed again.

This happens because useEffect only runs when one of its dependencies changes. In this case, the dependency array [actionData?.status] prevents the effect from triggering if the status is the same as before.

The Fix

The fix for this issue is simple - adjust the dependency array of your useEffect. Instead of depending solely on actionData?.status, you should include the entire actionData object in the dependency array. Here’s how the updated code looks:

useEffect(() => {
  let description = '';
  if (actionData?.status === "success") {
    description = "Post created successfully 🎉";
  } else if (actionData?.status === "failed") {
    description = "Failed to create post 😵‍💫";
  }
  if (description.length > 0) {
    toast({ description, duration: 2000 })
  }
}, [actionData]); // ✅ Adjusted dependency array
Enter fullscreen mode Exit fullscreen mode

This ensures that your toast notification is displayed every time you submit the form.

Why Write About This?

You might wonder why I’m sharing this seemingly minor mistake. Well, this is actually the second time I’ve made this, so by documenting it here, I hope to not only serve as a personal reference for myself, but also help others avoid making the same mistake.

Thanks for reading!

Top comments (1)

Collapse
 
mdawooddev profile image
Mohammed Dawood

I totally agree with you 💯