Match only specific ids in the url - reactjs

I am trying to setup the PageNotFound. The 2nd route should match only for ids ['1', '2', '3']; (these id values hwoever i get after the api call. So i save the values in redux store from inside the Home component). Now when i try and access a incorrect id then it should redirect to PageNotFound. If id in url is lets say 4 it should redirect to PageNotFound.
Do i impletement this is User component when it gets redirected or is there a way to set it up in the below App.js file itself ?
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Home from "./Pages/Home";
import User from "./Pages/User";
import PageNotFound from "./Pages/PageNotFound";
import "./App.css";
function App() {
return (
<div className="App">
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/user/:id" exact component={User} />
<Route path="*" exact component={PageNotFound} />
</Switch>
</Router>
;
</div>
);
}
export default App;

You may create generic component for validation purpose.
Solution should be like this
<Route path="/user/:id" exact component={MyCheckComponent} />
MyCheckComponent.jsx
const MyCheckComponent =(props) => {
const {id} = useParams()
const allowedIds = useSelector(s => s.user.allowedIds)
return allowedIds.includes(id) ? <User {...props} /> : <Redirect to="/not-found"/>
}
At the end you may eliminate MyCheckComponent using render prop of the route.

Related

React Router Dom how to redirect to Other App.js route when you are in any subRoute of any route [duplicate]

This question already has answers here:
React Router works only after refreshing the page
(5 answers)
Closed 1 year ago.
I'm new to react & react router dom v5, also my english is bad. Thank you in advance for helping me.
my problem:
I have 2 Main Routes in my App.js route
import { Suspense } from 'react';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
/* Pges */
import AdminContainer from './Pages/Admin/AdminContainer';
import PublicContainer from './Pages/Public/PublicContainer';
import NotFound from './Pages/NotFound'
import AuthContainer from './Pages/Auth/AuthContainer';
/* Protected Route */
/* Helpers */
function App() {
console.log("APP")
return (
<Suspense fallback={(<p>Loading</p>)}>
<Router>
<Switch>
<Route path="/auth" component={AuthContainer} />
<Route path="/admin" component={AdminContainer} />
<Route path="/*" component={PublicContainer} />
<Route path="*" component={NotFound} />
</Switch>
</Router>
</Suspense>
)
}
export default App;
the authcontainer have 2 sub routes
"/signin"
"/signup"
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
withRouter
} from "react-router-dom";
// PAGES
import Signin from "../Auth/Signin";
import Signup from "../Auth/Signup";
const AuthContainer = () => {
console.log("AUTH")
return (
<div>
<Router>
<Switch>
<Route exact path="/auth" component={Signin}/>
<Route exact path="/auth/signin" component={Signin}/>
<Route exact path="/auth/signup" component={Signup}/>
</Switch>
</Router>
</div>
);
};
export default withRouter(AuthContainer);
then the my publiccontainer have 3 sub routes
"/"
"/product"
"/mycart"
/* Dependencies */
import { Route, Switch, BrowserRouter as Router } from 'react-router-dom'
/* Components */
import Header from "../../Components/Header"
import Products from "./Products"
import Home from "./Home"
import UserProfile from "../User/AccountProfile"
import MyCart from '../Public/MyCart'
const PublicContainer = () => {
console.log("PUBLIC")
return (
<div>
<Router>
<Header />
<Switch>
<Route exact path='/' render={(props) => <Home />} />
<Route exact path='/products' render={(props) => <Products />} />
<Route exact path='/mycart' render={(props) => <MyCart isAuth={false} />} />
</Switch>
</Router>
</div>
)
}
export default PublicContainer
the my cart component will only render if isAuth is true, else it will redirect to "/auth/signin"
import React from 'react'
import { Redirect } from 'react-router'
const MyCart = ({isAuth}) => {
if(!isAuth)
return (<Redirect from='*' to='/auth/signin'></Redirect>)
return (
<div>
my cart
</div>
)
}
export default MyCart
The problem is, its trying to redirect to "/auth/signin" but it is still in the "/" page
When i hit reload it finally redirect to "/auth/signin"
How can i fix this issue, I really appreciate your help
UPDATE
this is overview of my planned routes
By the way i think when the mycart isAuth is false then it tries to Link to /auth/signin which causes the link in the top url to correctly point to auth signin, but after that it only checks the subroutes of the publiccontainer instead of checking the app.js routes
But when i reload it, it start searching the correct route from the app.js routes which return the expected route & page which is the sign in
I read a almost similar question in terms of only rendering the correct path when hitting refresh/reload
here React Router works only after refreshing the page
The problem was i'm wrapping the sub routes with a new router, so i tried removing the Router jsx that is wrapping the Switch> & other subroutes in both AuthContainer.js & PublicContainer.js
this is the updated AuthContainer.js
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
withRouter
} from "react-router-dom";
// PAGES
import Signin from "../Auth/Signin";
import Signup from "../Auth/Signup";
const AuthContainer = () => {
console.log("AUTH")
return (
<div>
<Switch>
<Route exact path="/auth/signin" component={Signin}/>
<Route exact path="/auth/signup" component={Signup}/>
<Route exact path="/auth" component={Signin}/>
</Switch>
</div>
);
};
export default withRouter(AuthContainer);
And this is the PublicContainer.js
/* Dependencies */
import { Route, Switch } from 'react-router-dom'
/* Components */
import Header from "../../Components/Header"
import Products from "./Products"
import Home from "./Home"
import UserProfile from "../User/AccountProfile"
import MyCart from '../Public/MyCart'
/* Protected */
const PublicContainer = ({toAuth}) => {
console.log("PUBLIC")
return (
<div>
<Header />
<Switch>
<Route exact path='/products' render={(props) => <Products />} />
<Route exact path='/profile' render={(props) => <UserProfile />} />
<Route exact path='/mycart' render={(props) => <MyCart />} />
<Route exact path='/' render={(props) => <Home />} />
</Switch>
</div>
)
}
export default PublicContainer

How to defend routes in reactJS

I came across a problem which I dont know how to fix. I dont even know where to start.
The problem is next : I have url "localhost:4000/" If I will type url "localhost:4000/homepage" It will redirect me to my home page,But i want to restrict this access if token is not preserved.
Here are my routes :
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import LogIn from "./components/LogIn/Login";
import Register from "./components/Register/Register";
import Homepage from './components/HomePage/HomePage'
import Profile from './components/Profile/Profile'
import Posts from './components/addPostUI/Posts'
import "./app.css";
function App() {
return (
<Router>
<div className="App">
<Switch>
<Route path={"/"} exact component={LogIn} />
<Route path={"/login"} component={LogIn} />
<Route path={"/registration"} component={Register} />
<Route path={'/homepage'} component={Homepage} />
<Route path={'/profile'} component={Profile} />
<Route path={"/posts"} component={Posts} />
</Switch>
</div>
</Router>
);
}
export default App;
Any suggestions on how to restrict access and defend my routes?
There are many ways to restrict your Routes conditionally. The basic approach you can follow here is:
<Router>
<Switch>
<Route
path='/homepage'
render = {() => {
if(accessToken || localStorage.getItem('accessToken')) {
return <Homepage />;
} else {
return <Redirect to='/login' />;
}
}}
/>
</Switch>
</Router>
You can follow along with these steps whenever there is a need for conditional routing.
First determine what you want to authenticate users by, then you can do the following inside the page you want to protect, before the page renders.
if (failed access condition) return <Redirect to='/some route you want to redirect to' />
Be sure to import Redirect like this:
import { Redirect } from 'react-router-dom'
Also Consider
If you have a database, be sure to restrict access to the data based on the access token as well and don't depend on client side code to protect data.

How to make the drawer appear only on private routes?

I am developing a system with a login, and I want the drawer to appear only on routes that are private. How can I do that, below is a code that I already tried and was not successful.
import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import Home from "./Home";
import Login from "./Login";
import Details from "./Details";
import { AuthProvider } from "./Auth";
import PrivateRoute from "./PrivateRoute";
import Drawer from "./components/Drawer";
const App = () => {
return (
<AuthProvider>
<Router>
<Route exact path="/login" component={Login} />
</Router>
<Router>
<RoutePrivate />
</Router>
</AuthProvider>
);
};
const RoutePrivate = () => {
return (
<Router>
<Drawer />
<PrivateRoute exact path="/" component={Home} />
<PrivateRoute exact path="/:id" component={Details} />
</Router>
);
};
export default App;
You could do conditional rendering of drawer
const RoutePrivate = () => {
return (
<Router>
{window.location.pathname !== '/login' ? <Drawer /> : null}
<PrivateRoute exact path="/" component={Home} />
<PrivateRoute exact path="/:id" component={Details} />
</Router>
);
};
Good luck
You can go with few options.
you can remove <Drawer /> from router and render it inside <PrivateRoute /> along with matched router component (Home or Details etc).
Inside Drawer component, you can check auth and render null if auth failed. This way public routes will never get to see Drawer compoennt.
create a common layout and put the router inside layout. Check this. Also I got a random codesandbox (not fully working) but you can see the code reference there.

React router show only route without components defined in my browser

Hello in my directions file I set my struct
header
navbar
and my switch
foote
const AppRouter = () => (
<BrowserRouter>
<Route path="/login" component={AuthPage} exact={true} />
<Route path="/dashboard/addProduct" component={AddProduct} exact={true} />
<div>
<Header/>
<Navigation/>
<Container maxWidth="lg" >
<Switch>
<Route path="/" component={LandingPage} exact={true} />
<Route path="/xd" component={AuthPage} exact={true} />
<Route component={NotFoundPage} />
</Switch>
</Container>
</div>
</BrowserRouter>
);
But I have two routes where I didn't want to show my header
footer
and nav bar
which are the login and addproduct routes
how could i do that?
This is a little bit hacky (just to match your current approach) since I'm assuming you just want to hide those components in only those 2 routes, You can use withRouter in your Header and Navigation components, withRouter will provide to you the location prop and you can have a condition like this:
import React from "react";
import { withRouter } from "react-router-dom";
const Navigation = props => {
const { location } = props;
const { pathname } = location;
if (pathname !== "/login" || pathname !== "/dashboard/addProduct" ) {
return (
// Component logic goes here
);
}
// if we're on those routes we should return null to not render anything
return null;
};
export default withRouter(Navigation);
If you want a more robust long term approach this answer could help:
How to hide navbar in login page in react router

react-router-dom match object isExact false

I am working on a react project. I try to access the url parameters in the Header component. However, it always returns empty.
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router'
import SamplePage from './pages/SamplePage';
import PropertyPage from './pages/PropertyPage';
import LoadingPage from './pages/LoadingPage';
import Header from './header/Header';
import ButtonGroup from './ButtonGroup';
import { Container } from 'semantic-ui-react';
import history from '../history';
const App = () => {
return (
<ConnectedRouter history={history}>
<div>
<Switch>
<Route path='/loading' exact component={LoadingPage} />
<Route component={Header} title='Sample page' />
</Switch>
<Container style={{ marginTop: '7em' }}>
<Switch>
<Route
path='/page/:pageType/properties/:propertyId'
exact
component={PropertyPage}
/>
<Route path='/page/:pageType' exact component={SamplePage} />
</Switch>
</Container>
<Switch>
<Route exact path='/loading' render={() => <div />} />
<Route component={ButtonGroup} />
</Switch>
</div>
</ConnectedRouter>
);
}
export default App;
I try to access url params in the Header component. The params is empty, and isExact is false. Can anyone help me with this? Thanks.
From screenshot of console.log, react-router is matching on
<Route component={Header} title='Sample Scorecard' />
This is correct behavior as Switch looks for the first match.
I suggest to not declare rendering for Header as a Route. i.e.
<Switch>
<Route path='/loading' exact component={LoadingPage} />
<Header title='Sample Scorecard' />
</Switch>
This way Switch will only render it when loading path isn't matched.
I still cannot figure out how to solve this issue. What I do to walk around this issue is to create a Higher Order Component. Header will be included in the HOC, then it has no problem to get the URL parameters.

Resources