I have created a login component on which I have all the logic stuff.
The login reducer is:
const openState = {
loggedIn: null,
user: null
}
export default (state = openState, action) => {
switch (action.type) {
case LOGIN:
return { ...state, loggedIn: true, user: action.payload }
case LOGOUT:
return { ...state, loggedIn: false, user: null }
default:
return openState
}
}
The Action :
export const logIn = (user) => {
return {
type: LOGIN,
payload: user
}
}
export const logOut = () => {
return {
type: LOGOUT
}
}
everything is working just fine but I'm not sure how to pass the loggedIn
and user
props from action into the routes component in order to secure all routes:
const MainRoutes = props => {
const { loggedIn } = props;
console.log(props.loggedIn)
return (
<Router history={history}>
<Baseline />
<Menu/>
<Container maxWidth="md">
<Switch>
<Route exact path="/Login" component={Login} />
<Route exact path="/Carousel" component={Carousel} />
<Route exact path="/Stepper" component={Stepper} />
<Route component={NotFound} />
</Switch>
</Container>
</Router>
);
}
const mapStateToProps = (state) => {
return { loggedIn: state.loggedIn };
};
export default connect(mapStateToProps)(MainRoutes);
If I'll console.log the loggedIn
props I get undefined :|
Based on loggedIn
I can create a logic into the routes component.
This means that users must first meet certain conditions before accessing that specific route. For instance, your application can require only logged-in users be able to visit the dashboard page. In this tutorial, you are going to learn how you create protected routes in a React application.
Protected Route 1 create a functional component that accepts component and other route details as props, and then 2 check a condition to confirm if user is authenticated or not. (In our case, we'll be getting isAutheticated from localStorage) 3 if the value is true, render the component, else, Redirect route to /signin page.
Preventing unauthorized users from accessing your React page is critical for security. Here's how to do it. Protected routes are those routes that only grant access to authorized users. This means that users must first meet certain conditions before accessing that specific route.
There is no direct thing in React-Router for this. You need to write a wrapper like this. However, I'm not sure what Navigate is in your code. "If you prefer to use a declarative API for navigation (ala v5's Redirect component), v6 provides a Navigate component." You can find more info here github.com/ReactTraining/react-router/blob/dev/docs/…
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)
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With