Inside my React JS project, I am working on the PrivateRoutes
.
I have gone through this example of private routing and authenticating using react-router-dom
.
https://reacttraining.com/react-router/web/example/auth-workflow
According to this documentation, they have created a PrivateRoute
as a stateless component.
But my requirement is to convert it to stateful React component as I want to connect my PrivateRoute
component to redux store.
Here is my code.
stateless component
import React from 'react';
import {Route, Redirect} from 'react-router-dom';
import {auth} from './Authentication';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
auth.isAuthenticated ? (
<Component {...props} />
) : (
<Component {...props} action="login"/>
)
}
/>
);
export default PrivateRoute;
I converted this component to stateful React
component like this.
stateful React component
import React from 'react';
import {Route, Redirect} from 'react-router-dom';
import {auth} from './Authentication';
import {connect} from 'react-redux';
class PrivateRoute extends React.Component {
render({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={props =>
this.props.customer.isAuthenticated ? (
<Component {...props} />
) : (
<Component {...props} action="login"/>
)
}
/>
);
}
}
export default connect(state => state)(PrivateRoute);
Here, I am reading the data from redux store to check whether the user is authenticated or not.
But the way I am converting the stateless component to stateful isn't correct.
Am I passing the arguments render({ component: Component, ...rest })
correctly?
Will connecting the PrivateRoute
with redux store create any problem with props
as state=>state
will map state
to props
as well as ...rest
will have props
object?
Not sure what is happening inside the code.
Update AppRouter.js
import React from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import {TransitionGroup, CSSTransition} from 'react-transition-group';
import PrivateRoute from './PrivateRoute';
import HomePage from './../components/HomePage';
import AboutUs from './../components/AboutUs';
import ContactUs from './../components/ContactUs';
import PageNotFound from './../components/PageNotFound';
import RestaurantList from '../components/RestaurantList';
import RestaurantMenu from '../components/RestaurantMenu';
import UserDetails from '../components/UserDetails';
import OrderConfirmation from '../components/OrderConfirmation';
import CustomerAccount from '../components/CustomerAccount';
import Logout from '../components/sections/Logout';
export default () => {
return (
<BrowserRouter>
<Route render={({location}) => (
<TransitionGroup>
<CSSTransition key={location.key} timeout={300} classNames="fade">
<Switch location={location}>
<Route path="/" component={HomePage} exact={true}/>
<Route path="/about" component={AboutUs} />
<Route path="/contact" component={ContactUs} />
<Route path="/restaurants" component={RestaurantList} />
<Route path="/select-menu" component={RestaurantMenu} />
<PrivateRoute path="/user-details" component={UserDetails} />
<PrivateRoute path="/order-confirmation" component={OrderConfirmation} />
<PrivateRoute path="/my-account" component={CustomerAccount} />
<PrivateRoute path="/logout" component={Logout} />
<Route component={PageNotFound} />
</Switch>
</CSSTransition>
</TransitionGroup>
)} />
</BrowserRouter>
);
}
In general, converting a stateless functional component (SFC) to a Component
is done like this:
Create the class
shell for it.
Copy the SFC's body to the render
method. If the SFC was an arrow function, add a return
as necessary to render
.
Change any references to props
in the render
method to this.props
(or just add const { props } = this;
at the top). SFCs receive their props in their arguments, but a component receives them as arguments to its constructor; the default constructor will save them as this.props
.
In your case, it's using destructuring on its arguments, so you could do the same with this.props
on the right-hand side of the destructuring:
const { component: Component, ...rest } = this.props;
That's it. In your code, you've added parameters to the render
function, but it doesn't get called with any arguments, and you've only changed props
to this.props
a bit haphazardly (including changing auth.isAuthenticated
to this.props.customer.isAuthenticated
for some reason).
So applying 1-3 above:
// #1 - the shell
class PrivateRoute extends React.Component {
// #2 - `render`, with the body of the SFC inside
render() {
// #3 - destructure `this.props`
const { component: Component, ...rest } = this.props;
// #2 (part 2) - add `return`
return <Route
{...rest}
render={props =>
auth.isAuthenticated ? (
<Component {...props} />
) : (
<Component {...props} action="login"/>
)
}
/>;
}
}
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