React-router - How to use multiple private routes? - reactjs

My project have 2 different roles and both need login.
So I created 2 login pages and 2 private routes are Auth and Trainee
The problem is even I type an url is not children of Auth route it will go through Auth then it all wrong after that
<BrowserRouter>
<Switch>
<Route
exact
path={LoginForAuthPath}
component={LoginForAuthComponent}
/>
<Route
exact
path={LoginForTraineePath}
component={LoginForTraineeComponent}
/>
<Auth>
<Route
exact
path={SomeAuthPath}
component={SomeAuthComponent}
/>
</Auth>
<Trainee>
<Route
exact
path={SomeTraineePath}
component={SomeTraineeComponent}
/>
</Trainee>
</Switch>
</BrowserRouter>
class Auth extends React.Component {
constructor(props) {
super(props);
this.state = {
loggedIn: isLoggedIn(),
};
}
render() {
return this.state.loggedIn ? (
<Route children={this.props.children} />
) : (
<Redirect to={LoginPath} />
);
}
}

The issue here is that Switch renders the first matching component/Route within its children.
Since Auth is rendered unconditionally and is a valid component, it stops matching after Auth is rendered and never reaches Trainee
You should perhaps change your implementation of Auth and Trainee so that they both use Route as the direct child
class Auth extends React.Component {
constructor(props) {
super(props);
this.state = {
loggedIn: isLoggedIn(),
};
}
render() {
const {component: Component, ...rest } = this.props;
return <Route {...rest} render={(rProps) => this.state.loggedIn? <Component {...rProps}/>: <Redirect to={LoginPath} />} />
}
}
Similarly change the implementation of Trainee and use it like
<BrowserRouter>
<Switch>
<Route
exact
path={LoginForAuthPath}
component={LoginForAuthComponent}
/>
<Route
exact
path={LoginForTraineePath}
component={LoginForTraineeComponent}
/>
<Auth
exact
path={SomeAuthPath}
component={SomeAuthComponent}
/>
<Trainee
exact
path={SomeTraineePath}
component={SomeTraineeComponent}
/>
</Switch>
</BrowserRouter>

Related

How hide component from another component start render through route on react

I would like to hide a component when another component is routing
for more specific, i have a fixed bottom nav that i want to hide when a component is been route by user, in this case its a comment box
My first option was trying on the parent component with browserhistory and history.listen, and componning a string with math.params for get a match between, and this change the state of parent, witch will hide the bottomnav, and the code wrote was trying through a cyclelife passing props, but nothing, anyone can help me please?
class App extends React.Component {
constructor(props){
super(props);
this.state = {
showBottomNav: true
}
this.hideBottomNav = this.hideBottomNav.bind(this)
}
hideBottomNav= () => {
this.setState({
showBottomNav: false
})
}
render() {
return (
<Router>
<NavBar />
<Switch>
<Route path='/' exact component={Home} />
<Route path='/wars' exact component={Tournament} />
<Route path='/shop' exact component={Shop} />
<Route path='/library' exact component={Library} />
<Route
path='/:id'
exact
render={ props => <ExpandedPost {...props} parentMethod={() => this.hideBottomNav()} />}
/>
</Switch>
<BottomNav />
</Router>
);
}
}
export default App;
And the children Component
export default function PostReview(props) {
const classes = useStyles();
useEffect(() => {
props.parentMethod()
},[props])
return (
<div>....

React Router: Excluding a route from root path [duplicate]

This question already has answers here:
How to create a protected route with react-router-dom?
(5 answers)
Closed 5 months ago.
I'm currently setting up basic authentication for my React app. I have an AppWithAuth class which wraps the normal App, and a Login page. My goal is to redirect to /login when a user is not authenticated, but allow them to visit any other route if they are, such as / (dashboard path), /users, etc.
The problem I have is that the app wishes to render the root directory, but will redirect to the Login if not Authenticated. But since the login route is included in the root directory render, the app endlessly redirects. Any way to achieve the desired effect? Here's the gist of my code:
App:
class App extends React.Component {
render() {
return (
<Router> {/* The main routes of the app, e.g. /users... */}
...
</Router>
)
}
}
AppWithAuth:
class AppWithAuth extends React.Component {
isAuthenticated = () => {
// suppose this returns true if user is authenticated, false otherwise
}
render() {
return (
<Router>
<Route path='login' component={Login} />
<Route path='/' render={props => {
return this.isAuthenticated ? (
<App />
) : (
<Redirect to='/login' />
)
}} />
</Router>
)
}
}
If you use Switch then you can match paths exclusively. In that case order matters - the first path to match will break the switch, just like the switch statement. You can also leverage exact attribute to match a path exactly if you need to. For example:
<Router>
<Switch>
<Route exact path="/login" component={Login} />
<Route
path="/"
render={props => {
return this.isAuthenticated ? (
<App />
) : (
<Redirect to="/login" />
);
}}
/>
<Route path="/home" component={App} />
</Switch>
</Router>
what about try to this?
make ProtectedRoute for authenticated users
export default ({ isAuthenticated, component: C, ...rest }) => {
if (isAuthenticated) {
<Route {...rest} render={props => <C {...props} />} />
} else {
return <Redirect to="/login" />
}
}
use Router, Route in App.js
import ProtectedRoute from './ProtectedRoute'
class App extends React.Component {
isAuthenticated = () => {
// suppose this returns true if user is authenticated, false otherwise
}
render() {
return (
<Router>
<Route path='login' component={Login} />
<ProtectedRoute path='/' component={Main} isAuthenticated={this.isAuthenticated()} />
</Router>
)
}
}
The ProtectedRoute is only accept for authenticated users any others redirect to /login

React routing - Routes independent of parent routing files

I am defining the routes in react
Global ones in the app-routes.js file and other in their respective components.
app.js
render() {
return (
<div className="App-wrap">
<AppRoutes/>
</div>
); }
app-route.js
export class AppRoutes extends React.Component {
render() {
return (
<Router>
<Switch>
<Route path="/" component={LayoutComponent} />
</Switch>
</Router>
);
}
}
layout-component.js
I have placed my header here for navigation
export class LayoutComponent extends React.Component {
render() {
return (
<LayoutWrap>
<HeaderComponent> </HeaderComponent>
<LayoutRoutes />
</LayoutWrap>
);
}
}
layout.routing.js
export class LayoutRoutes extends React.Component {
render() {
return (
<Switch>
<Route path="/" exact >
<Redirect to="/users"/>
</Route>
<Route path="/users" name="Users" component={UserComponent} />
<Route path="/permissions" name="Permissions" component={PermissionComponent} />
</Switch>
);
}
}
Now the issue is, when i am defining my child routes, my child routes are dependent on parent
i.e. i have to write parent's previous url in child.
If i change my app-routes.js path from "" to layout my routing will not work.
<Route path="/layout" component={LayoutComponent} />
How to solve the issue?
When you are defining your child Routes, you need to prefix the parent route path before it for these to work. For this you can make use of match.path from props like
export class LayoutRoutes extends React.Component {
render() {
const { match } = this.props;
return (
<Switch>
<Route path={match.path} exact render ={(props) => <Redirect to="/users"/>} />
<Route path=`${match.path}/users` name="Users" component={UserComponent} />
<Route path=`${match.path}/permissions` name="Permissions" component={PermissionComponent} />
</Switch>
);
}
}

How to pass data to a page within a <redirect> in React?

Right now I am redirecting to a new page using but I dont know how to pass the data to the new page. This is what I am doing:-
class ShopsCatOptions extends React.Component{
constructor(props){
super(props);
this.state={
shopd: this.props.shop,
redirect:false
};
}
render() {
if (this.state.redirect) {
return <Redirect push to="./shopdetail" data={this.state.redirect}/>;
}
return(
<div class="expndinnerm" onClick={this.handleOnClick}>
{
this.state.shopd
}
</div>
)
}
}
export default ShopsCatOptions
What is the right way to do it?
What i have done to acheive this is by using history prop,
this.props.history.push({
pathname:"/shopdetail",
state:{
key:"value"
}
});
And in the ShopDetail component you can access the object like,
this.props.location.state.key
Edit: To get history in your props, your main component should have ,
import { BrowserRouter, Route } from 'react-router-dom';
...
<BrowserRouter>
<Switch>
<Route path="/home" component={Home} />
<Route path="/user" component={User} />
<Route path="*" component={page404} />
</Switch>
</BrowserRouter>

Layout routes with react router

I'm trying to do layouts with react-router.
When my user hits / I want to render some layout. When my user hits /login, or /sign_up I want the layout to render, with the relevant component for /login or /sign_up rendered.
Currently, my App.js looks like this
return (
<div className={className}>
<Route path="/" component={Auth} />
<ModalContainer />
</div>
);
My Auth.js looks like this
return (
<AuthFrame footerText={footerText} footerClick={footerClick}>
<Route path="/login" component={LoginContainer} />
<Route path="/sign_up" component={SignUpContainer} />
</AuthFrame>
);
So AuthFrame will get rendered when I hit /, and then react router looks for login or sign_up to render the other containers.
However, when I hit /, only the AuthFrame will render.
I would like for / to be treated as /login.
How do I achieve this?
The Switch component is useful in these cases:
return (
<AuthFrame footerText={footerText} footerClick={footerClick}>
<Switch>
<Route path="/login" component={LoginContainer} />
<Route path="/sign_up" component={SignUpContainer} />
{/* Default route in case none within `Switch` were matched so far */}
<Route component={LoginContainer} />
</Switch>
</AuthFrame>
);
see: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Switch.md
I think you're forced to introduce a prop/state which indicates the status of your viewer. This means is he signed in or just a guest of your website.
Your router can't obviously render /login if you you hit / but the router allows you to redirect to another page:
class AuthContainer extends React.Component {
defaultProps = {
loggedIn: false
}
render() {
return <div>
<Route path="/login" component={LoginContainer}/>
<Route path="/sign_up" component={SignUpContainer}/>
</div>
}
}
class PublicHomePage extends React.Component {
render() {
return <div>
<Route path="/settings" component={SettingsComponent}/>
<Route path="/profile" component={ProfileComponent}/>
<Route path="/and_so_on" component={AndSoOnComponent}/>
</div>
}
}
class App
extends React.Component {
defaultProps = {
loggedIn: false
}
render() {
const {loggedIn} = this.props;
if (loggedIn) {
return <PublicHomePage/>
}
return <Route exact path="/" render={() => (
<Redirect to="/login"/>
)}/>
}
}
I hope this code works for you. It isn't quite perfect but it should give you an idea how you could solve your problem.
In your case I would probably manipulate a bit with Routes in react-router. This code in AuthFrame should do the trick:
return (
<AuthFrame footerText={footerText} footerClick={footerClick}>
{["/", "/login"].map((path, ind) =>
<Route exact key={ind} path={path} component={LoginContainer} />
)}
<Route exact path="/sign_up" component={SignUpContainer} />
</AuthFrame>);
Note the usage of exact on the routes, this is to prevent matching login component on /sign_up since it will also match / and prevent rendering both login and signup when accessing the root path (/).

Resources