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]);
// ...
}
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
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)
I totally agree with you 💯