Reputation: 35265
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;
Upvotes: 0
Views: 1028
Reputation: 3748
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.
Upvotes: 2