How to handle logout route in Redux?
Asked Answered
S

3

12

I want to define a URL that could be used to logout the user (dispatch an action that would logout the user). I have not found examples showing how to implement a route dispatching an event.

Shavers answered 11/1, 2016 at 11:11 Comment(7)
Why not just dispatch an action on a link click? Special route for logout is not necessaryExuberate
From the user's standpoint of view, I'd like to be able to access the logout function using an URL.Shavers
I guess if you have Redux, that you are working on a single-page-application, that can't work with Javascript. So, what's the point to have an exposed link for it?Exuberate
Again, as a "power user", I like to type URLs to perform operations such as being able to destroy my session. Whether the app is SPA or not, has little to do with it.Shavers
Well, just go to /api/logout page or something like this, that does actual logout on the backendExuberate
The "session" persists on the client side (window.localStorage). Thats a standard JSON Web Token authentication implementation. Backend is not aware of user session. REST, by definition, is stateless (en.wikipedia.org/wiki/Representational_state_transfer#Stateless).Shavers
Then your solution seems reasonable. This example in the React-router repo does the same. Redux-simple-router is a simple connector and doesn't have anything to help here.Exuberate
S
10

Define a route /authentication/logout:

import React from 'react';
import {
    Route,
    IndexRoute
} from 'react-router';
import {
    HomeView,
    LoginView,
    LogoutView
} from './../views';

export default <Route path='/'>
    <IndexRoute component={HomeView} />

    <Route path='/authentication/logout'component={LogoutView} />
    <Route path='/authentication/login' component={LoginView} />
</Route>;

Create a LogoutView that dispatches an action upon componentWillMount:

import React from 'react';
import {
    authenticationActionCreator
} from './../actionCreators';
import {
    connect
} from 'react-redux';
import {
    pushPath
} from 'redux-simple-router';

let LogoutView;

LogoutView = class extends React.Component {
    componentWillMount () {
        this.props.dispatch(authenticationActionCreator.logout());
        this.props.dispatch(pushPath('/'));
    }

    render () {
        return null;
    }
};

export default connect()(LogoutView);

The componentWillMount callback dispatches two actions:

  • To destroy user session.
  • To redirect user to the IndexRoute.
this.props.dispatch(authenticationActionCreator.logout());
this.props.dispatch(pushPath('/'));
Shavers answered 11/1, 2016 at 11:11 Comment(6)
I am not 100% sure whether thats how the logout scenario should be handled. Please suggest an edit or add your answer if this is not a canonical approach.Shavers
It would be better to split logout and pushPath actions. pushPath should be in componentDidMountExuberate
@Exuberate What is the reason for that?Shavers
To make things go right. Some components may also want to update and upon logout, but you are firing a route change immediately. It was only my personal point of view if you don't have issues here, that is okay to leave it as is.Exuberate
Thank you for clarification.Shavers
Probably should redirect after upon success ( if there is any server call ). We need some types of promise.Goner
B
10

Here is a more current implementation for such /logout page:

import { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { withRouter } from 'react-router'
import * as authActionCreators from '../actions/auth'

class LogoutPage extends Component {

  componentWillMount() {
    this.props.dispatch(authActionCreators.logout())
    this.props.router.replace('/')
  }

  render() {
    return null
  }
}
LogoutPage.propTypes = {
  dispatch: PropTypes.func.isRequired,
  router: PropTypes.object.isRequired
}

export default withRouter(connect()(LogoutPage))
Brahe answered 8/7, 2016 at 18:20 Comment(6)
Can you explain what makes this a "more current" implementation?Shavers
agree - I would not say this is a more current implementation but an alternative implementation using react-router over redux-simple-router.I assume this would fit most use cases using react-router which is more commonly used and includes the 'withRouter' functionality which was recently introduced, so why the comment. :-)Calenture
First, please note that this implementation will work both with or without redux-simple-router (which, by the way, was renamed to react-router-redux a while ago). You can use Redux-style actions if you like, but it's not needed and IMHO it's not strictly related to the original routing problem. This implementation also takes advantage of the recently introduced withRouter higher-order component to make it simpler :)Brahe
withRouter should be around connect, not the other way around (to prevent screen refresh problems)Poised
@Poised could you please elaborate?Brahe
Sure, react-router uses global context to navigate, this means that a navigation event doesn't impact props and therefore, a pure component wouldn't know it has to re-render. This means that you can navigate and "nothing happens". In order to prevent this, you can use withRouter, which supplies the location prop. This prop changes in case of a navigation event, the child React component will therefore re-render. That is why it has to be around the connect call, and not the other way around.Poised
B
7

Here is the most current implementation for /logout page:

import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";

import * as authActionCreators from "../actions/auth";

class LogoutPage extends Component {
  static propTypes = {
    dispatch: PropTypes.func.isRequired
  };

  componentWillMount() {
    this.props.dispatch(authActionCreators.logout());
  }

  render() {
    return (
      <Redirect to="/" />
    );
  }

}

export default connect()(LogoutPage);

Works for:

"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-redux": "^5.0.6",
"react-router-dom": "^4.2.2",
"prop-types": "^15.5.10",
Blip answered 30/8, 2017 at 2:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.