React router redirect after action redux
ReactjsReact RouterReduxRedux FrameworkReactjs Problem Overview
I'm using react-redux
and react-router
. I need to redirect after an action is dispatched.
For example: I have registration a few steps. And after action:
function registerStep1Success(object) {
return {
type: REGISTER_STEP1_SUCCESS,
status: object.status
};
}
I want to redirect to page with registrationStep2. How can I do this?
p.s. In history browser '/registrationStep2' has not been visited. This page appears only after successful result registrationStep1 page.
Reactjs Solutions
Solution 1 - Reactjs
With React Router 2+, wherever you dispatch the action, you can call browserHistory.push()
(or hashHistory.push()
if that’s what you use):
import { browserHistory } from 'react-router'
// ...
this.props.dispatch(registerStep1Success())
browserHistory.push('/registrationStep2')
You can do this from async action creators too if that is what you use.
Solution 2 - Reactjs
Have you checked out react-router-redux? This library makes it possible to sync react-router with redux.
Here is an example from the documentation of how you can implement the redirection with a push action from react-router-redux.
import { routerMiddleware, push } from 'react-router-redux'
// Apply the middleware to the store
const middleware = routerMiddleware(browserHistory)
const store = createStore(
reducers,
applyMiddleware(middleware)
)
// Dispatch from anywhere like normal.
store.dispatch(push('/foo'))
Solution 3 - Reactjs
Simplest solution for router version 4+: We use "react-router-dom": "4.3.1" It doesn't work with version 5+
export your browser history from the place where it was initialised and use browserHistory.push('/pathToRedirect'):
Package history must be installed(example: "history": "4.7.2"):
npm install --save history
In my project I initialise browser history in index.js:
import { createBrowserHistory } from 'history';
export const browserHistory = createBrowserHistory();
Redirect in the action:
export const actionName = () => (dispatch) => {
axios
.post('URL', {body})
.then(response => {
// Process success code
dispatch(
{
type: ACTION_TYPE_NAME,
payload: payload
}
);
}
})
.then(() => {
browserHistory.push('/pathToRedirect')
})
.catch(err => {
// Process error code
}
);
});
};
Solution 4 - Reactjs
To build on Eni Arinde previous answer's (I don't have the reputation to comment), here is how to use the store.dispatch
method after an async action :
export function myAction(data) {
return (dispatch) => {
dispatch({
type: ACTION_TYPE,
data,
}).then((response) => {
dispatch(push('/my_url'));
});
};
}
The trick is to do it in the action files and not in the reducers, since reducers should not have side effects.
Solution 5 - Reactjs
An updated answer using hooks; for router v5 users.
> Working on react-router-dom:5.1.2
.
> No installation of external package is required.
import { useHistory } from "react-router-dom";
function HomeButton() {
let history = useHistory();
function handleClick() {
history.push("/home");
}
return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}
You can use the history
as you're previously used to.
More more details and APIs - read the manual
Solution 6 - Reactjs
We can use "connected-react-router".
import axios from "axios";
import { push } from "connected-react-router";
export myFunction = () => {
return async (dispatch) => {
try {
dispatch({ type: "GET_DATA_REQUEST" });
const { data } = await axios.get("URL");
dispatch({
type: "GET_DATA_SUCCESS",
payload: data
});
} catch (error) {
dispatch({
type: "GET_DATA_FAIL",
payload: error,
});
dispatch(push("/notfound"));
}
};
};
Attention-- Please go to https://github.com/supasate/connected-react-router read the docs and set up the connected-react-router
first, and then use "push" from connected-react-router
.
Solution 7 - Reactjs
You can use {withRouter} from 'react-router-dom'
Example below demonstrates a dispatch to push
export const registerUser = (userData, history) => {
return dispatch => {
axios
.post('/api/users/register', userData)
.then(response => history.push('/login'))
.catch(err => dispatch(getErrors(err.response.data)));
}
}
The history arguments is assigned to in the component as the a second parameter to the action creator (in this case 'registerUser')
Solution 8 - Reactjs
signup = e => {
e.preventDefault();
const { username, fullname, email, password } = e.target.elements,
{ dispatch, history } = this.props,
payload = {
username: username.value,
//...<payload> details here
};
dispatch(userSignup(payload, history));
// then in the actions use history.push('/<route>') after actions or promises resolved.
};
render() {
return (
<SignupForm onSubmit={this.signup} />
//... more <jsx/>
)
}
Solution 9 - Reactjs
Here is the working copy of routing app
import {history, config} from '../../utils'
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import Login from './components/Login/Login';
import Home from './components/Home/Home';
import reducers from './reducers'
import thunk from 'redux-thunk'
import {Router, Route} from 'react-router-dom'
import { history } from './utils';
const store = createStore(reducers, applyMiddleware(thunk))
export default class App extends Component {
constructor(props) {
super(props);
history.listen((location, action) => {
// clear alert on location change
//dispatch(alertActions.clear());
});
}
render() {
return (
<Provider store={store}>
<Router history={history}>
<div>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
</div>
</Router>
</Provider>
);
}
}
export const config = {
apiUrl: 'http://localhost:61439/api'
};
import { createBrowserHistory } from 'history';
export const history = createBrowserHistory();
//index.js
export * from './config';
export * from './history';
export * from './Base64';
export * from './authHeader';
import { SHOW_LOADER, AUTH_LOGIN, AUTH_FAIL, ERROR, AuthConstants } from './action_types'
import Base64 from "../utils/Base64";
import axios from 'axios';
import {history, config, authHeader} from '../utils'
import axiosWithSecurityTokens from '../utils/setAuthToken'
export function SingIn(username, password){
return async (dispatch) => {
if(username == "gmail"){
onSuccess({username:"Gmail"}, dispatch);
}else{
dispatch({type:SHOW_LOADER, payload:true})
let auth = {
headers: {
Authorization: 'Bearer ' + Base64.btoa(username + ":" + password)
}
}
const result = await axios.post(config.apiUrl + "/Auth/Authenticate", {}, auth);
localStorage.setItem('user', result.data)
onSuccess(result.data, dispatch);
}
}
}
export function GetUsers(){
return async (dispatch) => {
var access_token = localStorage.getItem('userToken');
axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`
var auth = {
headers: authHeader()
}
debugger
const result = await axios.get(config.apiUrl + "/Values", auth);
onSuccess(result, dispatch);
dispatch({type:AuthConstants.GETALL_REQUEST, payload:result.data})
}
}
const onSuccess = (data, dispatch) => {
const {username} = data;
//console.log(response);
if(username){
dispatch({type:AuthConstants.LOGIN_SUCCESS, payload: {Username:username }});
history.push('/');
// Actions.DashboardPage();
}else{
dispatch({ type: AUTH_FAIL, payload: "Kullanici bilgileri bulunamadi" });
}
dispatch({ type: SHOW_LOADER, payload: false });
}
const onError = (err, dispatch) => {
dispatch({ type: ERROR, payload: err.response.data });
dispatch({ type: SHOW_LOADER, payload: false });
}
export const SingInWithGmail = () => {
return { type :AuthConstants.LOGIN_SUCCESS}
}
export const SignOutGmail = () => {
return { type :AuthConstants.LOGOUT}
}
Solution 10 - Reactjs
while using react-router-dom version +5 you can't use useHistory hook in redux(redux toolkit).
So if you want to redirect after an action is dispatched you can get your history "via useHistory() hook" in your current page(component) then pass the history along with your payload as an argument to redux. Hence you can easily manage your history in redux after an action is dispatched like this : history.push ("somewhere)