Hi there i have created a protected route in and passing navbar as parent component. then i passing child components in protected rout i want to hide navbar in some component on some action
Here is my protected.router.js code
import React from "react";
import { Route, Redirect } from "react-router-dom";
import Navbar from './component/Layouts/Navbar';
export const ProtectedRoute = ({
component: Component,
...rest
}) => {
return (
<Route
{...rest}
render={props => {
if (localStorage.getItem("loggedAsli") === "1") {
return <div> <Navbar/>
<Component {...props} /> </div>;
} else {
return (
<Redirect
to={{
pathname: "/login",
state: {
from: props.location
}
}}
/>
);
}
}}
/>
);
};
And this my App.js code
import React from "react";
import { BrowserRouter, Route } from "react-router-dom";
import { ProtectedRoute } from "./protected.route";
import Learn from "./component/Learn/Learn";
class App extends React.Component {
constructor(props) {
super();
this.updateUserLoginSetting = this.updateUserLoginSetting.bind(this);
this.state = {
userId: "",
instituteId: ""
};
}
updateUserLoginSetting = (userId, instituteId) => {
this.setState({ userId: userId, instituteId: instituteId });
};
render() {
return (
<BrowserRouter>
<div className="App">
<Route render={props => <Login />} exact path="/login" />
<ProtectedRoute exact path="/Learn" component={Learn} />
</div>
</BrowserRouter>
);
}
}
export default App;
How i can hide navbar in Learn Component
Please guide me.
is there any global state handling
You could just pass a prop (e.g. showNav) and use it inside ProtectedRoute
export const ProtectedRoute = ({
component: Component,
showNav = true, // added showNav prop
...rest
}) => {
return (
<Route
{...rest}
render={props => { // check if should showNav
if (localStorage.getItem("loggedAsli") === "1" && showNav) {
return <div> <Navbar/>
<Component {...props} /> </div>;
} else {
return (
<Redirect
to={{
pathname: "/login",
state: {
from: props.location
}
}}
/>
);
}
}}
/>
);
};
And pass false when it's Learn
// pass showNav as false to hide nav bar
<ProtectedRoute showNav={false} exact path="/Learn" component={Learn} />
Related
I tried to summarize my problem in the code below. My real code it is too big, so I developed another similar code in way to solve this problem.
I have a loggin page where the user has to type "True" or "False" to update the state fom this component.
I need to pass this state to the "Route" component, that will verify what page is going to be rendered. If the parameter received from the Login component is "True", then Home page will be rendered. If it is "False" Login page will be rendered.
From my understanding, I have to pass props from childreen to parent component, but I am not being able to solve this problem.
App.jsx (Component)
import React from 'react'
import { BrowserRouter } from 'react-router-dom'
import Routes from './Routes'
export default props =>
<BrowserRouter>
<div>
<Routes />
</div>
</BrowserRouter>
Routes.jsx (Component)
import React from 'react'
import { Switch, Route, Redirect} from 'react-router'
import Login from './Login';
import Home from './Home';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
isAuthenticated() ? (
<Component {...props} />
): (
<Redirect to={{pathname: "/login", state: {from: props.location }}} />
)}
/>
)
const Routes = () =>
<Switch>
<PrivateRoute path='/home' component={Home} />
<Route exact path='/login' component={Login} />
<Redirect from='*' to='/home' />
</Switch>
export default Routes;
Home.jsx (Component)
import React, { Component } from 'react'
export default class Home extends Component {
render (){
return (
<h1>This is the HOME page</h1>
);
}
}
Login.jsx (Component)
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import Routes from './Routes'
export default class Login extends Component{
constructor(props){
super(props);
this.state = {
userLoggedIn: false
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
e.preventDefault()
let stateName = e.target.name
let stateValue = e.target.value
console.log(e.target, e.target.value)
this.setState({ [stateName]: stateValue})
}
render(){
console.log('esse estado é',this.state.userLoggedIn)
return(
<div>
<div>This is the Login Page</div>
<label>State Test</label>
<input placeholder="true or false" onChange={e => this.handleChange(e)}></input>
<Link to={{pathname: "/home"}}>
<button >Go To Home Page</button>
</Link>
</div>
)
}
}
What do I expect?
When the user type "True" in the Login page, Home page must be rendered.
When the user type "False" in the Login page, Login page must be rendered.
Here is the working code and codesandbox link
If user enters false, then he will not be redirected as he is already on Login page.
import React, { Component } from "react";
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
withRouter
} from "react-router-dom";
function AuthExample() {
return (
<Router>
<div>
<AuthButton />
<ul>
<li>
<Link to="/home">Home Page</Link>
</li>
</ul>
<Route path="/login" component={Login} />
<PrivateRoute path="/home" component={Home} />
</div>
</Router>
);
}
const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
setTimeout(cb, 100); // fake async
},
signout(cb) {
this.isAuthenticated = false;
setTimeout(cb, 100);
}
};
const AuthButton = withRouter(({ history }) =>
fakeAuth.isAuthenticated ? (
<p>
Welcome!{" "}
<button
onClick={() => {
fakeAuth.signout(() => history.push("/"));
}}
>
Sign out
</button>
</p>
) : (
<p>You are not logged in.</p>
)
);
function Home() {
return <h3>This is the HOME page</h3>;
}
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
}
class Login extends Component {
state = {
redirectToReferrer: false,
input: ""
};
login = e => {
e.preventDefault();
if (this.state.input === "true") {
fakeAuth.authenticate(() => {
this.setState({ redirectToReferrer: true });
});
} else {
this.setState({ redirectToReferrer: true });
}
};
handleChange = ({ target }) => {
this.setState({ [target.name]: target.value });
};
render() {
let { from } = this.props.location.state || { from: { pathname: "/" } };
let { redirectToReferrer } = this.state;
if (redirectToReferrer) return <Redirect to={from} />;
return (
<div>
<div>This is the Login Page</div>
<label>State Test</label>
<br />
<input
placeholder="true or false"
name={"input"}
value={this.state.input}
onChange={this.handleChange}
/>
<br />
<button onClick={this.login}>Go To Home Page</button>
</div>
);
}
}
export default AuthExample;
Hope that helps!!!
When a user tries to view a private page(/products/1/edit), he will be redirected to the login component.
After login i want to redirect the user to the same product edit page. **The problem is that I am unable to get the location props in the component. It is returning as undefined.
** The code is as follows.
App.js
class App extends React.Component {
render() {
return (
<div className="App">
<AppRouter />
</div>
);
}
}
export default App;
AppRouter.js
import { ConnectedRouter } from 'react-router-redux';
...
class AppRouter extends Component {
componentDidMount() {
this.props.checkAlreadyLoggedIn();
}
render() {
const { token, location } = this.props;
return ((
<ConnectedRouter history={history}>
<Layout style={{ minHeight: '100vh' }}>
<Layout>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/login" render={ () => token && <Redirect to=
{
location.state && location.state.from ? location.state.from.pathname :
"/dashboard"
} /> || <Login />} />
<PrivateRoute path="/dashboard" component={Dashboard} />
...
</Switch>
</Layout>
</Layout>
</ConnectedRouter>
));
}
}
history.js
import createHistory from 'history/createBrowserHistory';
const history = createHistory();
export default history;
i am already defined the private route as follows
class PrivateRoute extends PureComponent {
static propTypes = {
token: PropTypes.string,
component: PropTypes.any
}
render() {
const { component: Component, ...rest } = this.props;
let token = utils.getUserToken();
return (
<Route
{...rest}
render={ () =>
(token && <Component {...this.props} />) ||
<Redirect to={{
pathname: '/login',
state: { from: this.props.location }
}}/>
}
/>
)
}
}
Only if i get the location.state.from.pathname, i will be able to redirect the user to the page that he tried to access prior to login.
Any idea on how to fix this?
This is the PrivateRoute implementation I use and it performs redirect:
import React from 'react';
import { Route, Redirect } from "react-router-dom";
import { isLoggedIn } from '../../utils/authHelper';
class PrivateRoute extends React.Component {
renderComponent = () => {
const { path, component: Component } = this.props;
return (
isLoggedIn()
? <Component {...this.props} />
: <Redirect to={{
pathname: '/login',
state: { from: path }
}} />
)
}
render (){
const { component: Component, ...rest } = this.props;
return (
<Route {...rest} render={this.renderComponent} />
)
}
}
export default PrivateRoute;
And usage is like:
<Switch>
<Route path='/login' component={LoginScreen} />
<PrivateRoute path='/profile' component={ProfileComponent} />
</Switch>
And on /login route you will get the original url via this.props.location.state.from:
...
doLogin(username, password)
.then(() => {
window.location.href = `/${this.props.location.state.from}`;
});
Using react hooks useHistory() method history.goBack()
...
login(userData);
history.goBack();
Hi there I have built a ProtectedRoute component and I wish to include it in my App component. While I see it work for many others, I'm not sure why Im the odd one out. Code Below:
const PrivateRoute = ({ component: Component, path, ...rest }) => {
return (<Route {...rest} render={(props) => (
firebaseApp.auth().onAuthStateChanged(user => {
if (user) {
<Component {...props} />;
} else {
<Redirect
to={{
pathname: "/",
state: {
prevLocation: path,
error: "You need to login first!",
},
}}
/>
}
})
)} />
)
}
class App extends Component {
displayName = App.name
constructor(props) {
super(props);
}
render() {
return (
<Layout>
<Route exact path='/' component={Home} />
<Route path='/signin' component={SignIn} />
<Route path='/signup' component={SignUp} />
<PrivateRoute path='/counter' component={Counter} />
<Route path='/fetchdata' component={FetchData} />
</Layout>
);
}
}
export default App;
The Routes render method is returning a function which it shouldn't
firebaseApp.auth().onAuthStateChanged
In your case you should use a React component and not a functional component.
const withAuth = (Component) => {
class AuthComp extends React.Component {
state={
loading: true,
user: null
}
componentDidMount() {
firebaseApp.auth().onAuthStateChanged(user => {
this.setState({loading: false, user})
});
}
render() {
if(loading) {
return <div>Loading...</div>
}
if(!loading && !user) {
return <Redirect
to={{
pathname: "/",
state: {
prevLocation: path,
error: "You need to login first!",
},
}}
/>
}
return <Component {this.props} />
}
}
}
const PrivateRoute = ({ component: Component, path, ...rest }) => {
return (<Route {...rest} component={withAuth(Component)} />)
}
I have created a reactJS app using create-react-app using Flux as an architecture where I want to have some routes accessible without being authenticated and some only accessible while authenticated. Using the flux design pattern I am passing the state of the store down through each component using props so the store state is available for all child components that require it.
I have studied the documentation here (the example is also pasted below) to try and understand how to achieve the above outcome in my app.
I can't see how I can adapt the example to pass state down to the component called within the protected route without doing this with an explicit name like how component is passed.I want to acheive...
Pass the component to PrivateRoute so it can be called if my user is authenticated.
Pass all props from the parent component to the component called by PrivateRoute (this is to allow me to keep cascading the store state down through the props and also to check in the store state if the user is logged in).
I think I am perhaps misunderstanding something fundamental here. Can anyone advise please?
import React from "react";
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
withRouter
} from "react-router-dom";
////////////////////////////////////////////////////////////
// 1. Click the public page
// 2. Click the protected page
// 3. Log in
// 4. Click the back button, note the URL each time
const AuthExample = () => (
<Router>
<div>
<AuthButton />
<ul>
<li>
<Link to="/public">Public Page</Link>
</li>
<li>
<Link to="/protected">Protected Page</Link>
</li>
</ul>
<Route path="/public" component={Public} />
<Route path="/login" component={Login} />
<PrivateRoute path="/protected" component={Protected} />
</div>
</Router>
);
const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
setTimeout(cb, 100); // fake async
},
signout(cb) {
this.isAuthenticated = false;
setTimeout(cb, 100);
}
};
const AuthButton = withRouter(
({ history }) =>
fakeAuth.isAuthenticated ? (
<p>
Welcome!{" "}
<button
onClick={() => {
fakeAuth.signout(() => history.push("/"));
}}
>
Sign out
</button>
</p>
) : (
<p>You are not logged in.</p>
)
);
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
const Public = () => <h3>Public</h3>;
const Protected = () => <h3>Protected</h3>;
class Login extends React.Component {
state = {
redirectToReferrer: false
};
login = () => {
fakeAuth.authenticate(() => {
this.setState({ redirectToReferrer: true });
});
};
render() {
const { from } = this.props.location.state || { from: { pathname: "/" } };
const { redirectToReferrer } = this.state;
if (redirectToReferrer) {
return <Redirect to={from} />;
}
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={this.login}>Log in</button>
</div>
);
}
}
export default AuthExample;
Here is a section from my actual code...
class Page extends React.Component{
// constructor(props) {
// super(props);
// }
render(){
return(
<Router>
<div>
<Route exact path="/" render={()=><HomePage {...this.props}/>}/>
<Route path="/login" render={()=><LoginPage {...this.props}/>}/>
<PrivateRoute exact path="/protected" component={Main} extra="Boo!"/>
</div>
</Router>);
}
}
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={(props) =>
(console.log(this.props.extra) || 1) ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
This.props.extra is undefined.
If you are looking for a way to pass extra props to the PrivateRoute you can do:
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={ (props) =>
( console.log(props.extra) || 1) ? (
<Component {...props} {...rest} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
then
<PrivateRoute exact path="/protected" component={Main} extra="Boo!"/>
and Main should now receive extra prop (together with path and exact).
I've been struggling with rewriting this react component to a pure function per my eslint error recommendations. My goal is to also get this to work with react router without it throwing a warning/error.
Here is the class component:
class PrivateRouteContainer extends React.Component {
render() {
const {
isAuthenticated,
component: Component,
...props
} = this.props
return (
<Route
{...props}
render={props =>
isAuthenticated
? <Component {...props} />
: (
<Redirect to={{
pathname: '/login',
state: { from: props.location }
}} />
)
}
/>
)
}
}
source: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-redux/examples/AuthExample.js
Here is my eslint error:
Here is my attempt:
const PrivateRouteContainer = (props) => {
const {
isAuthenticated,
isLoggingIn,
} = props;
return (
<Route
{...props}
render={() =>
(isAuthenticated || isLoggingIn
? <Component {...props} />
: (
<Redirect to={{
pathname: '/login',
state: { from: props.location },
}}
/>
))
}
/>
);
};
This doesn't seem to work as I'm getting the error:
Warning: You should not use and in the same route; will be ignored
Here are my route definitions if it helps:
import React from 'react';
import PropTypes from 'prop-types';
import { Route, Switch } from 'react-router';
import { connect } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { ConnectedRouter } from 'react-router-redux';
import PrivateRoute from './PrivateRoute';
import Login from '../containers/LoginPage';
import Home from '../containers/HomePage';
import List from '../containers/ListPage';
import Edit from '../containers/EditPage';
import { logout } from '../redux/auth/oauth/actions';
const ConnectedSwitch = connect(state => ({ location: state.routerReducer.location }))(Switch);
const mapStateToProps = state => ({
isLoggingIn: state.authReducer.isLoggingIn,
isAuthenticated: state.authReducer.isAuthenticated,
error: state.authReducer.error,
});
const Logout = connect(mapStateToProps)(({ dispatch }) => {
dispatch(logout());
return <Redirect to="/" />;
});
const Routes = props =>
(
<ConnectedRouter history={props.history}>
<ConnectedSwitch>
<Route path="/" exact component={connect(mapStateToProps)(Home)} />
<PrivateRoute path="/list" exact component={List} />
<PrivateRoute path="/edit" component={Edit} />
<Route path="/login" exact component={connect(mapStateToProps)(Login)} />
<Route path="/logout" exact component={Logout} />
</ConnectedSwitch>
</ConnectedRouter>
);
Routes.propTypes = {
history: PropTypes.shape({}).isRequired,
};
export default connect(mapStateToProps)(Routes);
This is just a typo as I think you understood "this" is not defined in a stateless component :
const {
isAuthenticated,
isLoggingIn,
} = props; // <-- remove this. here
const PrivateRouteContainer = (props) => (
<Route
{...props}
render={() =>
(props.isAuthenticated || props.isLoggingIn
? <Component {...props} />
: (
<Redirect to={{
pathname: '/login',
state: { from: props.location },
}}
/>
))
}
/>
)
Instead of passing authentication as props, have you considered creating a utils file, such as auth.js that easily returns if the user is validated or not?
If we tangle the authentication conditions within component disposition we're adding an additional layer which we're going to have to care about, which is having to care about the parent component's life cycle and how it evaluates to authentication. This also means you're passing to the <Route /> component, some props that it doesn't care or doesn't need to care about, and that could be problematic as well
To make things clearer, also try using the object destructuring property instead of declaring const inside of your component, as well as the rest operator. Pass to route only what route needs, and to <Component />, only what component needs. That could be causing errors,
The final result is something like this:
import { isAuthenticated } from 'utils/auth';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
isAuthenticated() ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/login' }} />
)
)}/>
);
I'm not sure if this is the best approach or not, but it seems to be working...
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Route } from 'react-router';
import { Redirect } from 'react-router-dom';
const RedirectToLogin = () => (
<Redirect to={{ pathname: '/login' }} />
);
const PrivateRouteContainer = props => (
<Route
{...props}
component={props.isAuthenticated || props.isLoggingIn ?
props.component :
RedirectToLogin}
/>
);
PrivateRouteContainer.propTypes = {
isAuthenticated: PropTypes.bool.isRequired,
isLoggingIn: PropTypes.bool.isRequired,
component: PropTypes.func.isRequired,
};
const PrivateRoute = connect(state => ({
isAuthenticated: state.authReducer.isAuthenticated,
isLoggingIn: state.authReducer.isLoggingIn,
}))(PrivateRouteContainer);
export default PrivateRoute;