Search code examples
reactjsreact-reduxreact-routerredux-formredux-saga

How to redirect to a different page after a redux action using react


I'm building a web app, and I want users to confirm their emails before they are able to sign in. I am using redux and have a redux action where I confirm the user. After I confirm the user, I want to reroute the user to the sign in page, with a two seconds timeout. I've included by redux action to confirm the user, as well as my Confirm component, and my App.js, so you can see the routing as well. For the routing, I have wrapped all my routes in a switch. I'd really appreciate any help, it would really mean a lot to me, as I am pretty stuck on this. Also, if you have any questions about my code, let me know. Thank you!

confirm action:

// Confirm User
export const confirm = (email, code) => async dispatch => {
  dispatch({
    type: CONFIRM_STARTED
  });
  try {
    const res = await axios.get(`/api/auth/confirm?email=${email}&code=${code}`)

    dispatch({
      type: CONFIRM_SUCCESS
    });


  } catch (err) {
    const errors = err.response.data.errors;

    if (errors) {
      errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
    }


    dispatch({
      type: CONFIRM_FAIL
    });
  }
}

Confirm component:

import React from "react";
import { connect } from 'react-redux';
import { confirm } from '../../actions/auth';



class Confirm extends React.Component {
  componentDidMount() {
    //console.log("test ()");
    let email = new URLSearchParams(this.props.location.search).get("email");
    let code = new URLSearchParams(this.props.location.search).get("code");
    this.props.confirm(email, code);
  }



  render() {
    return (
      <div style={{ marginTop: 50 }}>
        <div>
          {this.props.confirmed}
          {this.props.confirming}
        </div>
        <div>
          We have confirmed your account, you may now login!
        </div>
      </div>
    )
  }
}


const mapDispatchToProps = dispatch => ({
  confirm: (email, code) => dispatch(confirm(email, code))
})

const mapStateToProps = (state, ownProps) => ({
  confirmed: state.auth.emailConfirmed,
  confirming: state.auth.emailConfirming
})

export default connect(mapStateToProps, mapDispatchToProps)(Confirm);

App.js

import React, { Fragment, useEffect } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Navbar from './components/layout/Navbar';
import Landing from './components/layout/Landing';
import Login from './components/auth/Login';
import Register from './components/auth/Register';
import Alert from './components/layout/Alert';
// Redux
import { Provider } from 'react-redux';
import store from './store';
import { loadUser } from './actions/auth';
import setAuthToken from './utils/setAuthToken';
import Profile from './components/profile/Profile';
import PrivateRoute from './components/routing/PrivateRoute';
import CreateChat from './components/chat-form/CreateChat';
import JoinChat from './components/chat-form/JoinChat';
import Chat from './components/profile/Chat';
//import PostForm from './components/profile/PostForm';
import AboutChat from './components/profile/AboutChat';
import Post from './components/profile/Post';
import CommentForm from './components/profile/CommentForm';
import Confirm from './components/profile/Confirm';

import './App.css';

if (localStorage.token) {
  setAuthToken(localStorage.token);
}

const App = () => {
  useEffect(() => {
    store.dispatch(loadUser());
  }, []);

  return (
    <Provider store={store}>
      <Router>
        <Fragment>
          <Navbar />
          <Route exact path="/" component={Landing} />
          <section className="container">
            <Alert />
            <Switch>
              <Route exact path="/register" component={Register} />
              <Route exact path="/login" component={Login} />
              <PrivateRoute exact path='/profile' component={Profile} />
              <PrivateRoute exact path='/create-chat' component={CreateChat} />
              <PrivateRoute exact path='/join-chat' component={JoinChat} />
              <PrivateRoute exact path='/chat/:id' component={Chat} />
              <PrivateRoute exact path='/comment-form/:chatId/:postId' component={CommentForm} />
              <PrivateRoute exact path='/chat-details/:id' component={AboutChat} />
              <PrivateRoute exact path='/post/:chatId/:postId' component={Post} />
              <Route exact path='/confirm' component={Confirm} />
            </Switch>
          </section>
        </Fragment>
      </Router>
    </Provider>
  )
};

export default App;

Solution

  • Here is a simple example that might help. Click the Confirm button to imperatively push onto the history stack. Once you are "logged in", a timeout begins running and 3 seconds later you are declaratively "logged out" using the Redirect component and some conditional logic. You are subsequently returned to the Login page.

    Sandbox

    import React, { useEffect, useState } from "react";
    import ReactDOM from "react-dom";
    import {
      BrowserRouter,
      Route,
      Switch,
      useHistory,
      Redirect
    } from "react-router-dom";
    
    const rootElement = document.getElementById("root");
    
    function Login() {
      const history = useHistory();
      return (
        <div>
          <p>Login</p>
          <button onClick={() => history.push("/auth")}>Confirm</button>
        </div>
      );
    }
    
    function Auth() {
      const [deleteAuth, setDeleteAuth] = useState(false);
      useEffect(() => {
        setTimeout(() => setDeleteAuth(true), 3000);
      }, []);
      if (deleteAuth) return <Redirect to="/" />;
      else return <div>Auth</div>;
    }
    
    ReactDOM.render(
      <React.StrictMode>
        <BrowserRouter>
          <Switch>
            <Route exact path="/">
              <Login />
            </Route>
            <Route path="/auth">
              <Auth />
            </Route>
          </Switch>
        </BrowserRouter>
      </React.StrictMode>,
      rootElement
    );