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
Related
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 using React 16, React-router-dom 4 and Mobx in my app.
I have this code for a private route:
export default (props) => {
console.log('props from private',props)//Here i can see that the component doesn't contain the "history" prop.
const Component = props.component;
const match = props.computedMatch
if (isValidated()) {
return (
<div>
<div><Component {...props} match={match} /></div>
</div>
)
} else {
return <Redirect to="/login" />
}
};
This is the routing setup:
export const history = createHistory();
const AppRouter = () => (
<Router history={history}>
<Switch>
<PrivateRoute path="/" component={Chat} exact={true} />
<Route path="/login" component={Login} />
</Switch>
</Router>
);
For some reason, the history prop just doesn't exist in the private route, therefore i'm unable to use the this.props.history.push function, to redirect programatically. The prop does get passed to a "normal" route though.
What is wrong with my code?
Use below:
import {withRouter} from 'react-router-dom';
wrap component with withRouter.
withRouter(component_name)
My reactjs application has two types of Users namely Artist and Lovers. Some of my components are only accessible to artist and some are only accessible to lovers. So i need to implement Artist and User Routes that will help grand access only to the required User type.
And here is my Router Switch
<Switch>
<Route exact path='/' component={Home} />
<UserRoute authed={this.state.lover} path='/user-dash' component={About} />
<ArtistRoute authed={this.state.artist} path='/artist-dash' component={Contact} />
<Route path='/SignupUser' component={SignupUser} />
</Switch>
Here is my UserRoute code
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
export const UserRoute = ({ component: Component, authed, ...rest }) => (
<Route {...rest} render={props => (
authed
? <Component {...props} />
: <Redirect to={{ pathname: '/', state: { from: props.location } }} />
)} />
)
I want to be able to receive the value of authed in the UserRoute passed in the switch. I do not know why authed in the UserRoute always returns false.
even when this.state.lover passed to it is true. Please what am I doing wrong.
Thanks
Route.jsx
<Switch>
<Route exact path='/' component={Home} />
<Route path='/user-dash' component={AuthCheck(About)} /> // Wrap the component with HOC
</Switch>
AuthCheck.jsx
export default function(Component) {
class AuthCheck extends Component {
render() {
if (this.props.auth.payload) {
return <Component {...this.props} /> // Component if auth is true
} else {
return <Route path='*' exact={true} component={NotFound} /> // 404 if not auth
}
}
}
function mapStateToProps(state) {
return { auth: state.auth }
}
return connect(mapStateToProps)(AuthCheck)
}
Check the above example works with redux
Make sure to import AuthCheck in the Route.jsx file
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.
Here is my navigation component:
import React from 'react'
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {
type: 'signUp', // or login
showModal: false,
isLoggedIn: false,
}
}
...some code
render() {
const { showModal, type, isLoggedIn } = this.state
console.log(this.props.location); // all problem is this, I'm not getting it in console
return(
...some more code
)
}
}
export default withRouter(Navigation)
And here is where it it been used in app.js
class App extends React.Component {
render () {
return(
<Router>
<Fragment>
<Navigation /> // <= right there
<Switch>
<Route exact path='/' component={HomePage}/>
<Route exact path='/search' component={HomePage}/>
<Route component={Lost} />
</Switch>
</Fragment>
</Router>
)
}
}
I want to get updated route props like match and location and history in my <Navigation /> component but I get it only when the first time that component mounts on the DOM, in my other components I update the route using window.history.pushState but I am not able to get route props from withRouter after link in the browser is been updated.
I update route with window.history.pushState because:
I could not find any way to update just link in the address bar without showing user or redirecting user to new component with React router DOM (am I doing it in right way or not?)
based on that I then use window.location.pathname to add some specific stylings to some components)
Also, I read the entirety of this and this but I could not solve this issue. What am I doing wrong?
withRouter gives you the closest <Route>'s route props, and since the Navigation component is not inside a Route you will not get the route props.
You could e.g. put the Navigation component on a Route outside of the Switch that will always be visible.
Example
class App extends React.Component {
render() {
return (
<Router>
<Fragment>
<Route path="/" component={Navigation} />
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/search" component={HomePage} />
<Route component={Lost} />
</Switch>
</Fragment>
</Router>
);
}
}