Correct way of redirecting after successful async action: Passing "history" to thunk as argument VS using <Redirect> conditionally with Redux store?

580 views Asked by At

I've learned of 2 methods to redirect to a different page after executing an async action with Redux Thunk:

1-Method: Passing "history" object to the async action as argument.

In your component you define the "history" object with "useHistory" hook and pass it to your async action:

function Register(){
    const history = useHistory()
    const dispatch = useDispatch()
    
    function registerHandler(){
        dispatch(registerAsync(registerForm, history))\
    }

    return (
        // JSX Code
        <button onClick={registerHandler}>Register</button> 
    )
}

Then in your async action, you can use "history.push()" to redirect:

export function registerAsync(data, history){
    return async function (dispatch) {
        try {
            const response = await Axios.Post('api/register/', data)
            history.push('/register_success')
        } catch (e) {
            dispatch(registerError(e))
        }
    }
}

2-Method: Using the < Redirect > component that gets conditionally rendered depending on a Redux store value:

In the component you return conditionally if a store value is true:

function Register(){
    const dispatch = useDispatch()
    const registerSuccess = useSelector((store) => store.auth.registerSuccess)
    
    function registerHandler(){
        dispatch(registerAsync(registerForm, history))\
    }
    
    
    if (registerSuccess) {
        return <Redirect push to="/register_success"/>
    }

   return (
        // JSX Code
        <button onClick={registerHandler}>Register</button>
    )
}

And inside our Async action we dispatch an action that sets the "registerSuccess" to true:

export function registerAsync(data){
    return async function (dispatch) {
        try {
            const response = await Axios.Post('api/register/', data)
            dispatch(registerSuccess())
        } catch (e) {
            dispatch(registerError(e))
        }
    }
}

Reducer:

 case actionTypes.REGISTER_SUCCESS:
            newState.registerSuccess = true
            return newState

Does anyone know which of the 2 methods is correct and why?

Many thanks!

1

There are 1 answers

0
Saloumi On

If you are using react-router-dom v6, then you should use useNavigate instead of useHistory as in this example

https://stackoverflow.com/a/63921034/13218213

Though I found a nice solution by passing the navigate function to the handler (in my case I passed it to the asyncAction function

MyComponent.tsx


import {useNavigate} from 'react-router-dom';
import {useAppDispatch, actions } from 'store';


const MyComponent = () => {
    
const navigate = useNavigate();
const dispatch = useAppDispatch();

const handleConfirm = () => {
    dispatch(actions.slice.asyncActionFunction(navigate));
      };

return <></>
};

Then in the asyncAction (or asyncThunk) I did like this

async-actions.ts


import { NavigateFunction } from 'react-router-dom';

export function asyncActionFunction(navigate: NavigateFunction) {
  return async (dispatch: AppDispatch, getState: () => RootState) => {
 
   try{
    /**
    * you can now use navigate(to:string; options: {}) as following
    */
        navigate('/destination');
    } catch (e) {
      console.error(e);

    }
  };
}