Search code examples
reactjsreduxreact-router-dommernredux-toolkit

How to call navigate inside Redux Toolkit's actions in React js


I've a simple app built on redux-toolkit. I am dispatching createProduct actions which is working fine. I want to navigate to /products/ page form /products/new page after createProduct action. How can I use navigate (react-router-dom) to do this.

I tried this inside action but failes

 [createProduct.fulfilled]: (state, { payload }) => {
      toast.success('Product Created Successfully!');
      const navigate = useNavigate()
      navigate('/products')
      return {
        ...state,
        loading: false,
        products: state.products ? [...state.products, payload.product] : [payload.product]
      };
    },

I also tried passing navigate to payload but I encountered this error :

 You may not call store.getState() while the reducer is executing. The reducer has already received the state as an argument. Pass it down from the top reducer instead of reading it from the store.

I am dispatching createProduct like this

 const handleSubmit = async () => {
    console.log('formik.values', formik.values);
    dispatch(
      createProduct({
        ...formik.values,
        category: formik.values.category._id,
        subCategory: formik.values.subCategory._id
      })
    )
  };

Solution

  • Reducer functions are pure functions, you can't issue the navigation action from the reducer, but you can from the asynchronous action or in the calling component. React hooks are also only valid in React functions or custom hooks.

    Asynchronous actions return a Promise. You can chain from the resolved Promise, or await it, and issue the imperative navigation.

    const navigate = useNavigate();
    

    Using Promise chain:

    const handleSubmit = () => {
      dispatch(createProduct({
        ...formik.values,
        category: formik.values.category._id,
        subCategory: formik.values.subCategory._id
      }))
        .then(() => {
          navigate('/products');
        });
    };
    

    or async/await:

    const handleSubmit = async () => {
      try {
        await dispatch(createProduct({
          ...formik.values,
          category: formik.values.category._id,
          subCategory: formik.values.subCategory._id
        }));
        navigate('/products');
      } catch(error) {
        // handle any rejections/errors
      }
    };