Search code examples
javascriptreactjsreduxnext.jsredux-thunk

Can router.push be used from Redux thunk? Is it a good practice?


I have this anchor element:

<a
  className="btn btn-sm btn-circle"
  href={`https://www.facebook.com/sharer/sharer.php?u=${
    process.env.NEXT_PUBLIC_ENVIRONMENT == "prod"
      ? "https://tikex.com"
      : "https://tikex-staging.com"
  }/share/${organizationSlug}/${postId}&quote=${postSurveySchemaDTO?.caption}`}
  onClick={(e) => {
    dispatch(
      createShare({
        tempUserId: "e3445c3b-5513-4ede-8229-d258ed4418ae",
        postId,
      })
    );
  }}
>
  Megosztom
</a>

I tested many times, maybe one time only but seem than onclick and networking was not triggered in that case, 99% ok. Is it better if I trigger navigation also from onClick after networking was done?

Can I trigger router.push() from reducer / thunk?

Like this?

export const createShare = createAsyncThunk(
    `${namespace}/createShare`,
    async (props: any, { dispatch }) => {
        const { data } = await axios({
            method: 'post',
            url: 'share',
            data: props,
            headers: { crossDomain: true },
        }).then((res) => {
            router.push(`http://...`)
            return res
        })
        return data
    }
)

Solution

  • It seems like you have a race condition.

    1. the the <a> is trying to navigate the browser away to the href
    2. onClick has a dispatch(createShare(...)) trigger

    I would suggest preventing the default <a> event and manually choreograph the two separate events -

    onClick(e => {
      e.preventDefault() // stop the browser from trying to navigate away
      dispatch(
        createShare({
          ...
          thenNavigateTo: e.target.href // or whatever
        })
      )
    }
    

    If you need router to navigate, you can pass a thunk to the dispatched action -

    onClick(e => {
      e.preventDefault() // stop the browser from trying to navigate away
      dispatch(
        createShare({
          ...
          andThen: _ => router.push(e.target.href) // or whatever
        })
      )
    }