React Router 6 - pass data/state from action to loader with different route path

80 views Asked by At

I have an app with list of posts and post's detail. Now I am trying to figure out how to effectively show toast with some text after post is editted.

Let's say that I have:

import { Form } from "react-router-dom"

<PostDetail>
    const navigation = useNavigation()

    const isSubmitting = navigation.formData?.get("title") != null

    <Form>
        <input type="text" name="title" />
        <button>
            {isSubmitting ? "Saving..." : "Save"}
        </button>
    </Form>
</PostDetail>

After form submit do some stuff on Action function (https://reactrouter.com/en/main/route/action) and then redirect to the page with list of posts.

const postAction = async ({ request }: LoaderFunctionArgs) => {
    const formData = await request.formData()

    // call BE to update post and do some other stuff

    return redirect("/post/list")
}

After that I want to show some toast alert on the page with list of posts f.e. (Hey, your post has been updated...)

Am I able to send some info/status from action /post/:id to loader post/list?

1

There are 1 answers

0
mezerap On

I played with some solutions.

1) In postAction() do not return a redirect(), but some data ({status: "post-updated"}). Then in use useActionData() hook to get the status, show toast and the redirect force from a component via navigate('/post/list')

<PostDetail>
    const actionData = useActionData()
    const navigate = useNavigate();
    const navigation = useNavigation()

    const isSubmitting = navigation.formData?.get("title") != null

    if (actionData?.status === "post-updated") {
       // show toast message
       navigate('/post/list')
    }

    ....
</PostDetail>

This solution wasn't good for me, because I am also using useNavigation() hook to check "isSubmitting" state and display different text in my submit button. When the action function returned success status, useNavigation() returned state: "idle", not state: "submitting". So there was a little glitch (blink) in text, before the redirect was forced.

2) Second solution for me is add a search param directly into action function. And the toast message force in the component, where I check the search params. This is working but I don't like the messy code around. Like useEffect add useRef to prevent rendering etc.

const postAction = async ({ request }: LoaderFunctionArgs) => {
    ....
    return redirect("/post/list?alert=edit")
}
const PostList = () => {
  const [searchParams, setSearchParams] = useSearchParams()

  const render = React.useRef(true)
  React.useEffect(() => {
    if (render.current) {
      render.current = false
      if (searchParams.has("alert")) {
        // show toast with message...
        searchParams.delete("alert")
        setSearchParams(searchParams, { replace: true })
      }
    }
  }, [])

}

So my question is. Is there any other solution, how to pass some data between action and loader?

Thanks!