How to show error page if route is not available? [duplicate] - javascript

This question already has an answer here:
Redirect to Home page if URL not found
(1 answer)
Closed 5 months ago.
I have following implementation of React routing. How can I create Error page if path not found from routes list ?,
function App() {
return (
<div className="app-container">
<Switch>
{routes.map(({ key, path, crumbs, renderComponent }) => {
return (
<Route key={key} path={path}>
{renderComponent(crumbs)}
</Route>
)
})}
<Redirect to="/add-user" />
</Switch>
</div>
)
}

assuming its V5, It would be something as below...
Show a 404 Not found
<Route path="*">
<FourZeroFour />
</Route>
Redirect if not found
<Route path="*">
<Redirect to="/" /> // replace your home page path
</Route>
If you care, a good blog post on same ...

I think, we should to check the availability of key param. If key param was not exist, let's redirect user to Custom element 404 Page not found.
function App() {
return (
<div className="app-container">
<Switch>
{routes.map(({ key, path, crumbs, renderComponent }) => {
return (
if(key){
<Route key={key} path={path}>
{renderComponent(crumbs)}
</Route>
}
else{
<CustomElement404PageNotFound />
}
)
})}
<Redirect to="/add-user" />
</Switch>
</div>
)
}
Thank you

You can do it with put Route with path "*" append to last one.

Related

Matched leaf route at location "/" does not have an element. This means it will render an <Outlet /> with a null value, so resulting in an empty page

the return statement gives a warning and addTodo & todos dont load. Switch is not supported anymore so I've replaced it with Routes but don't know how handle that return part
Does anybody know how do I solve this issue?
return (
<>
<Router>
<Header title="To Do List" />
<Routes>
<Route exact path= "/" render={() => {
return (
<>
<AddTodo addTodo = {addTodo} />
<Todos todos = {todos} onDelete={onDelete} />
</>
)
}
}>
</Route>
<Route exact path = "/about" element = {<About/>} />
</Routes>
<Footer />
</Router>
</>
);
Click to view warnings screenshot

How to redirect user to a diferent path if token is expired

I'm making a simple site for a project, and i want to redirect player to a login page if the token is expired, but I'm not really sure how to do it properly, here's what I've tried, im using react-jwt to check the token
function App() {
return (
<div style={{display:'flex', flexDirection:'column', height:'100vh'}}>
<Navbar/>
<div style={{display:'flex', flex:1}}>
<Routes>
<Route path="/login" element ={<LoginForm/>} />
<Route path="/signUp" element ={<SignUpForm/>} />
<Route path="/addMovie" element= {<AddMovie/>} />
<Route path="/" element={isExpired(localStorage.getItem('token') ? <FilmList/> : <LoginForm/> )} />
<Route path="/details" exact element ={<MovieDetails/>} />
</Routes>
</div>
</div>
);
}
or something like
<Route path="/"
render={props=>{
if(isExpired(localStorage.getItem('token'))){
return <Navigate to='/login'/>;
}
return <FilmList/>
}}
/>
The first one just returns nothing, and the second one gives a warning in console:
Matched leaf route at location "/" does not have an element. This
means it will render an with a null value by default resulting in an
"empty" page.
Is there a way to make it work ?
In react-router-dom v6 gone are custom route components, and the Route component must have a valid ReactElement on the element prop. A function is incorrect. Your second snippet is close.
Create an AuthWrapper to conditionally render an Outlet for a nested route or a redirect.
const AuthWrapper = () => {
return isExpired(localStorage.getItem('token')
? <Navigate to="/login" replace />
: <Outlet />;
};
Wrap any routes you want to protect into a Route rendering the AuthWrapper.
function App() {
return (
<div style={{display:'flex', flexDirection:'column', height:'100vh'}}>
<Navbar />
<div style={{display:'flex', flex:1}}>
<Routes>
<Route path="/login" element={<LoginForm />} />
<Route path="/signUp" element={<SignUpForm />} />
<Route path="/addMovie" element={<AddMovie />} />
<Route element={<AuthWrapper />}>
<Route path="/" element={<FilmList />} />
</Route>
<Route path="/details" element={<MovieDetails />} />
</Routes>
</div>
</div>
);
}
One solution would be to use the Redirect component from react-router-dom.
Fo into your FilmList component and in the rendering part do the following check:
if (isExpired(localStorage.getItem('token')){
return <Redirect to='/login' />
}
before you return your 'normal' FilmList
FOR RRDv6 that doesn't support Redirect you can use the Navigate component:
if (isExpired(localStorage.getItem('token')){
return <Navigate to='/login' replace={true} />
}

React Router path var with other paths as well, React cant tell the difference

I am setting up react router for different link in my project but the problem is I need react router to tell the difference between a user username variable and other paths.
For example:
baseUrl/admin
baseUrl/daniel
React doesnt know the difference. I will have a list of usernames in a db and would return an error if the user doesnt exist then that means the page does not exist.
This is my code:
class App extends Component{
render(){
return (
<Router>
<Route exact path="/" render={props => (
<React.Fragment>
<h1>Hey</h1>
</React.Fragment>
)}
/>
<Route exact path="/admin" render={props => (
<React.Fragment>
<h1>admin</h1>
</React.Fragment>
)}
/>
<Route path="/:user" component={UserComponent}
/>
</Router>
);
}
}
You can use the match.url property to choose which component render, for example:
<Route path="/:user" render={props => {
if(props.match.url === '/admin') {
return (
<React.Fragment>
<h1>Hey</h1>
</React.Fragment>
)
} else return (<UserComponent {...props} />)
}} />

Adding Redirects programmatically to React Router

I'm trying to add a bunch of redirects given an array of old routes and new routes so I came out with this component:
const redirectUrls = [
{ oldUrl: '/robin', newUrl: '/users' },
{ oldUrl: '/batman', newUrl: '/courses' }
];
export default Redirects = () => (
redirectUrls.map((url, index) => <Route key={index} exact path={url.oldUrl} render={() => <Redirect to={url.newUrl} />} />)
);
Which works fine, but I wanted it to be simplier so I removed the Route and left only the redirect like this:
export default Redirects = () => (
redirectUrls.map((url, index) => <Redirect key={index} exact from={url.oldUrl} to={url.newUrl} />))
But it won't work, all the redirects take me to the last route, which in this case is /courses, and its weird because if I do this:
<Switch>
...
<Route path='/users' exact component={users} />
<Route path="/courses" exact component={CoursesList} />
<Redirect from='/robin' to='/users' />
<Redirect from='/batman' to='/courses' /> // having them like this works fine
</Switch>
So it makes no sense for them fail when I create them with a map and I haven't found anything that leads to the cause nor to a solution.
You need to wrap the exported redirects in a switch:
const Redirects = () => {
return (
<Switch>
{redirectUrls.map(url => (
<Redirect from={url.oldUrl} to={url.newUrl} />
))}
</Switch>
);
};
export default Redirects;
That's only if you actually need to make a component out of them. It's not totally clear what you need and are looking for since export default Redirects = () => is invalid syntax. If you just want to bundle them as some variable you can do:
export const Redirects = redirectUrls.map(url => <Redirect from={url.oldUrl} to {url.newUrl} />);
// App.js
<Switch>
<Route path='/users' exact component={users} />
<Route path="/courses" exact component={CoursesList} />
...
{Redirects}
</Switch>
Did you try this with exact props
<Switch>
...
<Route path='/users' exact component={users} />
<Route path="/courses" exact component={CoursesList} />
<Redirect exact from='/robin' to='/users' />
<Redirect exact from='/batman' to='/courses' /> // having them like this works fine
</Switch>
Reference https://github.com/ReactTraining/react-router/issues/4837

React Router path wrongly matches

I'm using React v4.2 for my app, and it seems not to be matching the correct path for the routes:
<Provider store={store}>
<BrowserRouter>
<div>
<Switch>
<Route path="/login" render={(props) => {
if (isAuthenticated()) {
return <Redirect to='/' />;
} else {
return <LoginForm {...props}/>
}
}
} />
<EnsureLoggedInContainer>
<Route exact path="/group" render={(props) => {
debugger;
return <GroupList {...props}/>
}
}/>
<Route exact path="/group/new" render={(props) => {
debugger;
return <GroupList {...props} modal={rr}/>;
}
} />
</EnsureLoggedInContainer>
</Switch>
</div>
</BrowserRouter>
</Provider>
I have some links in the app, on which I click and I redirect the client to new URL:
_onSubmit(values) {
const { history } = this.props;
this.props.createGroup(values, ({status}) => history.push('/group'));
}
I inspect the values of props.history.location.pathname and props.match.path and they don't match. Why is this happening? Why is the correct route not matched?
Update 1
The code for EnsureLoggedInContainer:
class EnsureLoggedInContainer extends Component {
componentDidMount() {
if (!isAuthenticated()) {
dispatch(setRedirectUrl(currentURL))
this.props.history.replace("/login")
}
}
render() {
if (isAuthenticated()) {
return(
<div>
<AppNavBar />
<ComponentsNavBar />
{this.props.children}
</div>
);
} else {
return <noscript />;
}
}
}
export default EnsureLoggedInContainer;
Update 2
I changed the router configuration code to the following:
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<div>
<Switch>
<Route exact path="/login" render={(props) => {
if (isAuthenticated()) {
return <Redirect to='/' />;
} else {
return <LoginForm {...props}/>
}
}
} />
<Route exact path="/register" render={(props) => {
if (isAuthenticated()) {
return <Redirect to='/' />;
} else {
return <RegisterForm {...props}/>
}
}
} />
<EnsureLoggedInContainer>
<Route exact path="/group" component={GroupList} modal={newGroupModal}/>
<Route exact path="/group/new" component={GroupList}/>
<Route component={Home} />
</EnsureLoggedInContainer>
</Switch>
</div>
</BrowserRouter>
</Provider>
, document.querySelector('.container'));
And changed the last line of EnsureLoggedInContainer to :
export default withRouter(EnsureLoggedInContainer);
But still, I get Home always being rendered, and random URLs being matched to unrelated routes (e.g. /group/new)
As per the documentation:
A match object contains information about how a matched
the URL. match objects contain the following properties:
params - (object) Key/value pairs parsed from the URL corresponding to the dynamic segments of the path
isExact - (boolean) true if the entire URL was matched (no trailing characters)
path - (string) The path pattern used to match. Useful for building nested <Route>s
url - (string) The matched portion of the URL. Useful for building nested <Link>s
while
Locations represent where the app is now, where you want it to go, or
even where it was.
so if you are on say /group/new, location.pathname will give you /group/new whereas match.path will give your the Route path defined for the component in which you log it if it is matched
I finally managed to resolve the issue by using the private route pattern.

Categories

Resources