0

I am trying to setup a simple authentication redirection with React and React Router.

Here are important packages and their versions I am using:

{
  "react": "^16.3.1",
  "react-dev-utils": "^5.0.1",
  "react-dom": "^16.3.1",
  "react-redux": "^5.0.7",
  "react-router-dom": "^4.3.0-rc.2",
  "redux": "^3.7.2",
}

This is what I was to achieve:

1. If user is not signed in and     going to /signin -- allow
2. If user is     signed in and     going to /signin -- redirect to /
3. If user is not signed in and not going to /signin -- redirect to /signin
4. If user is     signed in and not going to /signin -- allow

With the following code, redirection seems to be happening -- I see correct url in browser.

However, for the case user is signed in and is going to /signin I do see browser's URL changes to / but the Dashboard component is not rendered.

Here is relevant code:

app.js

import React, { Component } from "react";
import { Fabric } from "office-ui-fabric-react/lib/Fabric";
import { BrowserRouter as Router } from "react-router-dom";
import SmartRoute from "./smart-route";
import Header from "./ui/header";
import Dashboard from "./dashboard";
import SignIn from "./auth/signin";
import styles from "./app.scss";

class App extends Component {
  render() {
    return (
      <Router>
        <Fabric>
          <Header />
          <section className={styles.main}>
            <SmartRoute exact={true} path="/" component={Dashboard} />
            <SmartRoute exact={true} path="/signin" component={SignIn} />
          </section>
        </Fabric>
      </Router>
    );
  }
}

export default App;

smart-route.js

import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";

const renderComponent = (props, isAuthenticated, Component) => {
  const path = props.match.path;
  if (path === "/signin" && !isAuthenticated) return <Component {...props} />;
  if (path === "/signin" && isAuthenticated) return <Redirect to="/" />;
  return isAuthenticated ? <Component {...props} /> : <Redirect to="/signin" />;
};

const SmartRoute = ({ component: Component, isAuthenticated, ...rest }) => (
  <Route
    {...rest}
    render={props => renderComponent(props, isAuthenticated, Component)}
  />
);

const mapStateToProps = state => ({
  isAuthenticated: state.session.authUser !== null
});

export default connect(mapStateToProps)(SmartRoute);

dashboard.js

import React from "react";
const Dashboard = () => <section>Dashboard</section>;
export default Dashboard;
3
  • @MotiKorets adding push={true} doesn't help Commented Apr 15, 2018 at 0:08
  • Yes, going directly to / does work fine, I can see Dashboard Commented Apr 15, 2018 at 0:15
  • Possible Duplicate of React router changes url but not view Commented Apr 15, 2018 at 8:12

1 Answer 1

2

The problem is update blocking. To solve it you should use with withRouter HOC like this

import { withRouter } from 'react-router'
//.. 
export default withRouter(connect(mapStateToProps)(SmartRoute))

The reason it is happening is redux implements shouldComponentUpadte method which is unaware of location changes (and thus will not rerender the SmartRoute component). To overcome this you can pass location as a prop to SmartRoute (more efficient but not always straightforward) component or wrap it with withRouter (quick and dirty but might have performance issues). Read the doc for more in depth discussion.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.