I am trying to create a conditional route by creating a ProtectedRoute component as described by the chosen answer of this question.
The condition comes from the props passed into the ProtectedRoute component. Please have a look at the component and routing code below.
import React, {Component} from "react";
import { Route } from 'react-router-dom';
import { Redirect } from 'react-router';
class ProtectedRoute extends Component {
render() {
const { component: Component, ...props } = this.props
return (
<Route
{...props}
render={props => (
this.props.profile.name === "admin" ?
<Component {...props} /> :
<Redirect to='/login' />
)}
/>
)
}
}
export default ProtectedRoute;
The following is how I achieve the routing in a separate side navigation bar component. The profile object is passed as props to this component from App.js.
<main>
<Route path="/" exact component={props => <Home/>} />
<ProtectedRoute path="/dashboard" component={props => <Dashboard profile={this.props.profile} />} />
</main>
The error I am getting when running the above application is: TypeError: _this2.props.pofile is undefined. However, when I put a Route instead of ProtectedRoute i.e.
<Route path="/dashboard" component={props => <Dashboard profile={this.props.profile} />} />,
the application works as expected.
Could someone please assist me by pointing out what I am doing wrong? That would be much appreciated.
Inside Route's render property you use an arrow function which means that context inside it is bound to ProtectedRoute's instance. this.props inside render resolve to props of ProtectedRoute in other words. To solve this issue you need to pass profile to ProtectedRoute instead of Dashboard:
<main>
<Route path="/" exact component={props => <Home/>} />
<ProtectedRoute path="/dashboard" profile={this.props.profile} component={props => <Dashboard />} />
</main>
The reason why _this2.props.pofile is undefined - you haven't passed it to ProtectedRoute component, however, you passed it to Dashboard.
The right way to pass it is:
<ProtectedRoute path="/dashboard" profile={this.props.profile} component={props => <Dashboard profile={this.props.profile} />} />
By the way, it is not the best practice to pass JSX as a prop, better to pass it as children:
<ProtectedRoute path="/dashboard" profile={this.props.profile}>
<Dashboard profile={this.props.profile} />
</ProtectedRoute>
and then inside of ProtectedRoute just render {this.props.children}.
On this error TypeError: _this2.props.pofile is undefined it's pofile and not profile
Some where you define the wrong typo maybe.
Related
Here is mycode of the file PrivateRoute.js
import React from "react";
import {Route,Redirect} from "react-router-dom"
import {isAuthenticated} from "./index"
const PrivateRoutes = (props)=>{
return(
isAuthenticated()?(<Route
render={ (props) =>
<component {...props}/>} />):
(<Redirect to={{ pathname:"/signin"}}/>)
// <h1>hey there</h1>
)
}
export default PrivateRoutes;
In this code it is saying that value of props is read but never used but iam using it in render function,destructuring is also not working here.
Here isAuthenticated() is my boolean function . If it evaluates to true i want to get on more route to user dashboard.
This is how my routes.js file looks like
import React from 'react'
import {BrowserRouter,Route,Switch} from "react-router-dom";
import AdminRoutes from './auth/helper/AdminRoutes';
import PrivateRoutes from './auth/helper/PrivateRoutes';
import Home from './core/Home';
import AdminDashboard from './user/AdminDashBoard';
import Signin from './user/Signin';
import Signup from './user/Signup';
import UserDashboard from './user/UserDashBoard';
function Routes() {
return (
<BrowserRouter>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path="/signup" component={Signup} />
<Route exact path="/signin" component={Signin} />
<PrivateRoutes component="UserDashboard" exact path="/user/dashboard"/>
<AdminRoutes exact path="/admin/dashboard" component={AdminDashboard}/>
</Switch>
</BrowserRouter>
)
}
export default Routes
Help me to solve this problem.
This is because you have declared *two functions, each taking a props object argument, but only the inner/nested function's props is referenced.
Rename the nested props to something else like routeProps and spread both to the rendered component. Remember also that valid React component names are PascalCased.
Example:
const PrivateRoutes = ({ component: Component, ...props }) => {
return isAuthenticated()
? (
<Route
render={(routeProps) => (
<Component {...props} {...routeProps} />
)}
/>
) : <Redirect to={{ pathname:"/signin"}}/>;
}
Then also fix the PrivateRoutes component use to pass a value React component reference instead of a string.
<Switch>
<Route path="/signup" component={Signup} />
<Route path="/signin" component={Signin} />
<PrivateRoutes component={UserDashboard} path="/user/dashboard" />
<AdminRoutes path="/admin/dashboard" component={AdminDashboard} />
<Route path='/' component={Home} />
</Switch>
I found online how to create a costumed private route,
However, I'm getting an error
"Cannot read property 'state' of undefined" on line 12
I'm kinda new to react and I'm having trouble understanding props vs this.
Router.js
import React, { Component } from 'react';
import { Route, BrowserRouter, Redirect } from "react-router-dom";
import Login from './Authentication/Login';
import Register from './Authentication/Register';
import PageRouter from './page/PageRouter';
import Profile from './page/Profile';
import Rankings from './page/Rankings';
import Shop from './page/Shop';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={
(props) => (
this.state
? <Component {...props} />
: <Redirect to='/login' />
)} />
)
class Router extends Component{
constructor(props){
super(props);
this.state = {
login: false,
}
}
render(){
return(
<div>
<BrowserRouter>
<Route exact path="/" component={ Register }></Route>
<Route path='/register' component={ Register }/>
<Route path="/login" component={ Login } />
<PrivateRoute path='/home' component={ PageRouter } />
<Route path ='/profile' component={ Profile } />
<Route path = '/rankings' component={ Rankings } />
<Route path = '/shop' component={ Shop }/>
</BrowserRouter>
</div>
);
}
}
export default Router;
Any information would help. Thanks!
This isn't a React issue. The key you're missing here is understanding JavaScript context. Right now PrivateRoute's lexical scope is the global or window object (or if in strict mode undefined). You currently have no state on that object. If you want a way to utilize your Router class' state, then I would suggest you pass in some prop to PrivateRoute via Router.
So if you wanted to access the login property on state try something like:
<PrivateRoute path='/home' component={ PageRouter } isLoggedIn={this.state.login} />
then your PrivateRoute would have access to a prop called isLoggedIn which you could use in your ternary.
"Cannot read property 'state' of undefined" on line 12 I'm kinda new to react and I'm having trouble understanding props vs this.
Props is (in simple terms) a collection of attibutes that your component needs, eg: <MyComponent name="xxx" address="yyy"/> where name and address can be accessed by this.props.name or this.props.address respectively.
Keyword this is a different concept altogether. this referring to the component itself. It means, you can access its (component) state, props, or methods that is defined inside the component class
I don't know if this is related to your issue or not, but I noticed that your sample code is coming from a tutorial (https://tylermcginnis.com/react-router-protected-routes-authentication/).
Below is my implementation of PrivateRoute:
const PrivateRoute = ({ component: Component, ...rest }: {component: any}) => (
<Route {...rest} render={(props) => (
fakeAuth.isAuthenticated === true
? <Component {...props} />
: <Redirect to={{
pathname: '/login',
state: { from: props.location }
}} />
)} />
)
PrivateRoute.propTypes = {
component: PropTypes.any,
location: PropTypes.string,
path: PropTypes.string
};
The state properties is not this.state. It is a parameter from Redirectof react-router-dom
I have several components to protect authentication. Then I made a new component called ProtectedRoute. In this ProtectedRoute function I only catch properties that are thrown, but somehow I only get the state from React-Context, and the props I send are unreadable, when in console.log() it is undefined.
ProtectedRoute.js:
import React from 'react'
import { Route, Redirect } from 'react-router-dom'
import { withAuth } from './Context/AuthContext'
function ProtectedRoute(props) {
const {component: Component, ...rest} = props
console.log(Component)
return(
props.isLoggedIn ? <Route {...rest} component={Component} /> : <Redirect push to="/" />
)
}
export default withAuth(ProtectedRoute)
App.js:
render() {
return (
<BrowserRouter>
<AuthContextProvider>
<Switch>
<Route exact path="/" component={Login} />
<ProtectedRoute path="/portal" component={Main} />
</Switch>
</AuthContextProvider>
</BrowserRouter>
)
}
I have imported all required component btw, but if I change ProtectedRoute to normal <Route> by react-router, it can render component Main.
Is there something wrong with my code?
I'm working on a ReactJS project. I have 3 components in the main page "Index component" as follows,
Nav-
Featured-
Footer
My Nav component has 2 links to 2 different components.
My Switch is as follows,
<Switch>
<Route path="/home" component={props => <Index {...props} />} />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route path="/cart" component={Cart} />
<Redirect from="/" to="home" />
</Switch>
I also have my Index component as follows,
<React.Fragment>
<Search />
<Nav history={history} />
{this.homePageComponents()}
<Route
path="/home/bedding"
component={props => (
<Bedding beddingProducts={this.beddingProducts()} {...props} />
)}
/>
<Route
path="/home/bath"
component={props => (
<Bath bathProducts={this.bathProducts()} {...props} />
)}
/>
<Route path="/home/search" component={Search} />
</React.Fragment>
I'm trying to render the Nav component to both Bath and Bedding products but whenever I import it and use it there it gives me an Error saying this.props.history.replace is undefined.
This is the project's link.
https://github.com/MaxOffline/beetle
I think you can solve your issue with using "withRouter" wrapper component which react-router provide to wrap your Nav component.
https://reacttraining.com/react-router/web/api/withRouter
If you console.log(this.props) in the render method of nav.jsx you'll see that it contains a history object but that there is no replace method on that object.
You may be looking for the this.props.history.push method?
I found a very simple way to fix the problem.
All I needed to do is render components to the homepage conditionally so I simply added the following helper method to my "Index" Component.
homePageComponents = () => {
const featuredProducts = this.state.products.filter(
product => product.featured === true
);
if (this.props.history.location.pathname === "/home") {
return <Featured featuredProducts={featuredProducts} />;
}
};
I was looking for the simplest way to render the same component but from different paths.
I have the following so that both "/" and "/login" render the Login component.
import React from "react";
import { Route, Switch, Redirect } from 'react-router-dom';
import './App.scss';
import Login from "../../login/Login";
const App = () => {
return (
<div className="App">
<div className="App-container">
<Switch>
<Route exact path={["/", "/login"]} component={() =>
<Login login={true} />}/>
<Redirect to="/" />
</Switch>
</div>
</div>
);
}
export default App;
This does appear to work, however, it returns an error in the console.
Warning: Failed prop type: Invalid prop 'path' of type 'array' supplied to 'Route', expected 'string'.
I'm trying to do this...
<Route exact path={"/"} component={() => <Login login={true} />}/>
<Route exact path={"/login"} component={() => <Login login={true} />}/>
But with a shorter method, is this possible with react-router-dom? Any help would be greatly appreciated
You could create an array that contains the paths / and /login and use map on that array to render the same thing for both paths.
<Switch>
{["/", "/login"].map(path => (
<Route
key={path}
exact
path={path}
render={() => <Login login={true} />}
/>
))}
<Redirect to="/" />
</Switch>
If you wish to render the same component on the several routes, you can do this by specifying your path as a regular expression
lets say you want to display 'Home' component for 'Home', 'User' and 'Contact' components then here is code.
<Route path="/(home|users|contact)/" component={Home} />