I am using a private route to navigate to a route after the user has logged in. However, I am facing an issue. I don't know why but my router is not transitioning to the desired route. Here's my code:
Routes.js
...
...
<PrivateRoute
authenticated={localStorage.getItem("isAuthenticated")}
path="/dashboard"
component={DashBoard}
exact
></PrivateRoute>
PrivateRoute.js
const PrivateRoute = ({ component: Component, authenticated, ...rest }) => (
<Route
{...rest}
render={props =>
authenticated ? (
<Component {...rest} {...props} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: props.location }
}}
/>
)
}
/>
);
export default PrivateRoute;
Login.js
localStorage.setItem("isAuthenticated", true);
this.props.history.push('/dashboard');
Any help would be appreciated. Thanks!
So, I found the solution.
authenticated={localStorage.getItem("isAuthenticated")}
the above was invoking the method at application bootstrap due to which I was having the value of null being stored in my authenticated variable so, I changed it to arrow function and passed the argument without invoking it like below:
authenticated={() => localStorage.getItem("isAuthenticated")}
Can you just try it?
PrivateRoute.js
const PrivateRoute = ({ component: Component, authenticated, ...rest }) => {
console.log("authenticated",authenticated)//is it true or false?
if (authenticated=="true")
return (
<Route {...rest}>
{" "}
<Component {...rest} {...props} />
</Route>
);
else
return (
<Redirect
to={{
pathname: "/",
state: { from: props.location },
}}
/>
);
};
export default PrivateRoute;
Related
Hei Guys,
I got a strange problem that is stopping my development progress for days now.
In my React App I'm using React-Router (Browser Router).
Everthing is working fine (Link, Route, Switch) except Redirect.
redirect is changing the URL but not Rendering the 'new' component. E.g. I got a login screen and after Submit I want to redirect to user screen. Url is changing to URL but screen stays empty (The Sidenav is rendered but not the component, that shows the users information).
Does anybody know how to solve this? There are no errors in console.
Body Component:
<Switch>
<Route exact path="/">
<Home />
</Route>
<PrivateRoute path="/user" component = {User} />
<Route path="/login">
<Login/>
</Route>
<Route path="/register">
<Register />
</Route>
<NotFound />
</Switch>
Private Route:
const PrivateRoute = ({ component: Component, user, ...rest }) => {
return (
<Route {...rest} render={
props => {
if (user) {
return <Component {...rest} {...props} />
} else {
return <Redirect to={
{
pathname: '/login',
state: {
from: props.location
}
}
} />
}
}
} />
)
}
export default PrivateRoute;
Return Value of the render method of Login Screen, this part should be rendered when logged in:
return (
<Route render={
props => {
return <Redirect to={
{
pathname: '/user',
state: {
from: this.props.location
}
}
} />
}
}
/>
);
On Reloading everthing workls perfectly.
Using of Private Route also works.
No Typos.
regards
Manuel
You should not return a Route at your render method but rather a Redirect directly.
so sth like
return (
<>
{isLoggedIn ?
<Redirect to={{
pathname: '/user',
state: { from: this.props.location }
}} />
: LOGIN_FORM_HTML
}
</>
)
See the below function i am creating the Auth routes and getting the children undefined and shows blank page. In App.js i am using the private route as you can see below and when i use simple Route instead of PrivateRoute its shows the Login component
<PrivateRoute exact path="/" name="Login" render={props => <Login {...props}/>} />
Here is is My PrivateRoute.js. When i console the children its shows undefined
function PrivateRoute({ children, ...rest }) {
const token = cookie.get('token');
return (
<Route
{...rest}
render={({ location }) =>
!token ? (
children
) : (
<Redirect
to={{
pathname: "/dashboard",
state: { from: location }
}}
/>
)
}
/>
);
}
export default Private Route;
I usually use something like it. Let me know if it works for you.
Here is my privateRoute.js component:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { isAuthenticated } from 'auth';
export default function PrivateRoute({ component: Component, ...rest }) {
return (
<Route {...rest} render={
props => (
isAuthenticated() ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/', state: { from: props.location } }} />
)
)} />
);
}
Here I have another file in the root auth.js:
export const isAuthenticated = () => {
return Boolean(localStorage.getItem('jwttoken'));
}
export const login = ({email, password}) => {
// Logic
localStorage.setItem('jwttoken', 'jkdsalkfj');
return true;
}
export const logout = () => {
localStorage.removeItem('jwttoken');
}
You can call it like:
<PrivateRoute
component={ProjectPage}
path="/project/:id"
/>
Children refer to what's inside the tag
<PrivateRoute>
<PrivateComponent/>
</PrivateRouter>
Here your children would be <PrivateComponent/>
You're not passing anything inside your PrivateRoute in your example. So you'll have undefined
I am writing a HOC for public route and private route. If the route is private and the user is authenticated then let him/her enter that page else redirect to login component. If the route is public and the user is not authenticated then show the page and also show the login page if the user is not authenticated but user is authenticated and still goes to login page then redirect the user to root page. This is working fine. But if i use the render instead of component, then it does not work. I could make it work only if i pass the component from the props called component of react-router.
How can i make it work if user user render props?
Here is my code
<Switch>
<PrivateRoute
exact
path="/"
render={() => <Home name="something" />} {/* this does not work */}
/>
<PrivateRoute exact path="/demo" component={Demo} />
<PublicRoute restricted={true} path="/auth" component={Authentication} />
</Switch>
PublicRoute.js
const PublicRoute = ({component: Component, restricted, ...rest}) => {
return (
<Route
{...rest}
render={props =>
isLogin() && restricted ? <Redirect to="/" /> : <Component {...props} />
}
/>
)
}
PrivateRoute.js
const PrivateRoute = ({component: Component, ...rest}) => {
return (
<Route
{...rest}
render={props =>
isLogin() ? <Component {...props} /> : <Redirect to="/auth/login" />
}
/>
)
}
Also if there is any additional things to improve, please do suggest me.
The problem is that in your custom routes you are always using the component prop. So when passing the render prop it is overruled by the one in your custom route and thus trying to render the provided component.
When you modify it like the function below, it will work. It also extracts the render prop and if it's a function it will use that instead of the component prop.
const PrivateRoute = ({component: Component, render, ...rest}) => {
const renderContent = props => {
if (!fakeAuth.isAuthenticated) {
return (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
return (typeof render === 'function') ? render(props) : <Component {...props} />
}
return (
<Route {...rest} render={renderContent} />
);
}
I'm trying to set up protected routes using react router v4.
I have the following, which works fine.
function PrivateRoute({ component: Component, authed, ...rest }) {
return (
<Route
{...rest}
render={props =>
authed === true ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/', state: { from: props.location } }} />
)
}
/>
);
}
However, when I change this code to:
type PrivateRouteProps = {
component: Component,
};
const PrivateRoute = ({ component, authed, ...rest }: PrivateRouteProps) => (
<Route
{...rest}
render={props =>
authed === true ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/', state: { from: props.location } }} />
)
}
/>
);
I get the error: TypeError: instance.render is not a function. When I change to (note the component: Component), everything works:
const PrivateRoute = ({ component: Component, authed, ...rest }) => (
<Route
{...rest}
render={props =>
authed === true ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/', state: { from: props.location } }} />
)
}
/>
);
The render function of App.js is as follows:
render() {
return this.state.loading === true ? (
'loading'
) : (
<BrowserRouter>
<div>
{this.renderHeader()}
<Switch>
<Route exact path="/" component={LandingPage} />
<PrivateRoute
authed={this.state.authed}
path="/home"
component={HomePage}
/>
<Route component={PageNotFoundPage} />
</Switch>
</div>
</BrowserRouter>
);
}
Why does the arrow function with PrivateRouteProps not work as expected?
In your second example you try to render the component you passed in with
<Component {...props}/>
From the way you defined your flow type I guess that you imported Component like this:
import React, {Component} from 'react'.
That means that Component does not refer to the component passed in the component prop but still to the class Component imported from react because you did not shadow it anywhere inside your functional component. Even if you imported Component in your first example it would still work because you shadowed the name Component with the value of the prop component. In the second example you did not do that.
This is why you get the error because the react class Component neither has a render() method nor does it have any other functionality you expected there.
You need to assign the prop component to another name that is capitalized, e.g. Node and then render that variable. Note that the name needs to be capitalized. Otherwise it will be interpreted as usual html node and not as a react component:
type PrivateRouteProps = {
component: Component,
};
const PrivateRoute = ({ component: Node /* assign it to a capitalized name */, authed, ...rest }: PrivateRouteProps) => (
<Route
{...rest}
render={props =>
authed === true ? (
{/* Do not use `Component` here as it refers to the class imported from react and not to your component */}
<Node {...props} />
) : (
<Redirect to={{ pathname: '/', state: { from: props.location } }} />
)
}
/>
);
You could of course also use Component as a name which will shadow the name Component from the outer scope but this is bad practice as it often leads to confusion.
I have a PrivateRoute component that try to render a Component as follows:
import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
const PrivateRoute = ({ component, loggedIn, ...rest }) => (
<Route
{...rest}
render={props =>
loggedIn ? (
<Component {...props} />
) : (
<Redirect
to={{ pathname: '/login', state: { from: props.location } }}
/>
)}
/>
);
export default PrivateRoute;
And I use this component like this:
<PrivateRoute loggedIn={!!token} path="/user" component={User} />
It gives me the error as the title. I wonder where could I go wrong?
Thank you in advance.
You have unpacked the component that you passed to PrivateRoute as component:
const PrivateRoute = ({ component, loggedIn, ...rest }) => (
// HERE ^
but then you use Component (note the capital C) which is imported from react to render it.
<Component {...props} />
And that imported Component doesn't have any render method. Hence the error you get.
To fix you need to rename your unpacked component like the following:
const PrivateRoute = ({ component: Comp, loggedIn, ...rest }) => (
// HERE ^
<Route
{...rest}
render={props =>
loggedIn ? (
<Comp {...props} />
// HERE ^
) : (
<Redirect
to={{ pathname: "/login", state: { from: props.location } }}
/>
)
}
/>
);