How to add protected routes in react redux
As others already described, you had better to create a Protected Route to accomplish what you want. You simply redirect the user to the Login route if he/she is not logged in.
Here is my implementation: (codesandbox)
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
const ProtectedRoute = ({
path,
component: Component,
render,
loggedIn,
...rest
}) => {
return (
<Route
path={path}
{...rest}
render={(props) => {
if (loggedIn) {
return Component ? <Component {...props} /> : render(props);
}
return (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
);
}}
/>
);
};
const mapStateToProps = (state) => {
const { loggedIn } = state.auth;
return {
loggedIn
};
};
export default connect(mapStateToProps)(ProtectedRoute);
You could simply define a custom ProtectedRoute
component that'll be connected to redux state. In your case it should map state.auth.loggedIn
and state.auth.user
to props and perform a Redirect
if those values are falsy:
import React from "react";
import { Route, Redirect } from "react-router-dom";
import PropTypes from "prop-types";
const ProtectedRoute = (props) => {
const { redirectPath, component, user, loggedIn, ...routeProps} = props;
const Component = component;
const isAccessible = Boolean(user) && loggedIn;
return (
<Route
{...routeProps}
render={props => {
if (isAccessible) return <Component {...props} />;
return <Redirect to={{ pathname: redirectPath || "/Login" }} />;
}}
/>
);
};
ProtectedRoute.propTypes = {
path: PropTypes.string.isRequired,
redirectPath: PropTypes.string,
component: PropTypes.oneOfType([
PropTypes.shape({ render: PropTypes.func.isRequired }),
PropTypes.func
]),
};
const mapStateToProps = (state) => {
return {
loggedIn: state.auth.loggedIn,
user: state.auth.user
};
};
export default connect(mapStateToProps)(ProtectedRoute);
With this in place your MainRoutes
won't need connect
anymore:
const MainRoutes = props => {
return (
<Router history={history}>
...
<Container maxWidth="md">
<Switch>
<Route exact path="/Login" component={Login} />
<ProtectedRoute exact path="/Carousel" component={Carousel} />
<ProtectedRoute exact path="/Stepper" component={Stepper} />
<Route component={NotFound} />
</Switch>
</Container>
</Router>
);
}
export default MainRoutes;
Update:
If you want to keep auth
state after page refresh you'll need to perform some extra setup of your redux store. The main idea is to subscribe on every action and put a fresh copy of state into localStorage
or cookies
and also to persist initialState
from selected storage before your app boots up. Here is an example:
function getFromStorage(key) {
try {
return JSON.parse(window.localStorage.getItem(key)) || {};
} catch (err) {
return {};
}
}
const initialState = getFromStorage("APP_STATE");
const store = createStore(
rootReducer,
initialState, // should go after root reducer
...
);
store.subscribe(() => {
window.localStorage.setItem("APP_STATE", JSON.stringify(store.getState()));
});
And here's the working sandbox (bootstrapped by SuleymanSah)