React-Router: No Not Found Route? - javascript

Consider the following:
var AppRoutes = [
<Route handler={App} someProp="defaultProp">
<Route path="/" handler={Page} />
</Route>,
<Route handler={App} someProp="defaultProp">
<Route path="/" handler={Header} >
<Route path="/withheader" handler={Page} />
</Route>
</Route>,
<Route handler={App} someProp="defaultProp">
<Route path=":area" handler={Area} />
<Route path=":area/:city" handler={Area} />
<Route path=":area/:city/:locale" handler={Area} />
<Route path=":area/:city/:locale/:type" handler={Area} />
</Route>
];
I have an App Template, a HeaderTemplate, and Parameterized set of routes with the same handler (within App template). I want to be able to serve 404 routes when something is not found. For example, /CA/SanFrancisco should be found and handled by Area, whereas /SanFranciscoz should 404.
Here's how I quickly test the routes.
['', '/', '/withheader', '/SanFranciscoz', '/ca', '/CA', '/CA/SanFrancisco', '/CA/SanFrancisco/LowerHaight', '/CA/SanFrancisco/LowerHaight/condo'].forEach(function(path){
Router.run(AppRoutes, path, function(Handler, state){
var output = React.renderToString(<Handler/>);
console.log(output, '\n');
});
});
The problem is /SanFranciscoz is always being handled by the Area page, but I want it to 404. Also, if I add a NotFoundRoute to the first route configuration, all the Area pages 404.
<Route handler={App} someProp="defaultProp">
<Route path="/" handler={Page} />
<NotFoundRoute handler={NotFound} />
</Route>,
What am I doing wrong?
Here's a gist that can be downloaded and experimented on.
https://gist.github.com/adjavaherian/aa48e78279acddc25315

DefaultRoute and NotFoundRoute were removed in react-router 1.0.0.
I'd like to emphasize that the default route with the asterisk has to be last in the current hierarchy level to work. Otherwise it will override all other routes that appear after it in the tree because it's first and matches every path.
For react-router 1, 2 and 3
If you want to display a 404 and keep the path (Same functionality as NotFoundRoute)
<Route path='*' exact={true} component={My404Component} />
If you want to display a 404 page but change the url (Same functionality as DefaultRoute)
<Route path='/404' component={My404Component} />
<Redirect from='*' to='/404' />
Example with multiple levels:
<Route path='/' component={Layout} />
<IndexRoute component={MyComponent} />
<Route path='/users' component={MyComponent}>
<Route path='user/:id' component={MyComponent} />
<Route path='*' component={UsersNotFound} />
</Route>
<Route path='/settings' component={MyComponent} />
<Route path='*' exact={true} component={GenericNotFound} />
</Route>
For react-router 4 and 5
Keep the path
<Switch>
<Route exact path="/users" component={MyComponent} />
<Route component={GenericNotFound} />
</Switch>
Redirect to another route (change url)
<Switch>
<Route path="/users" component={MyComponent} />
<Route path="/404" component={GenericNotFound} />
<Redirect to="/404" />
</Switch>
The order matters!

In newer versions of react-router you want to wrap the routes in a Switch which only renders the first matched component. Otherwise you would see multiple components rendered.
For example:
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
Route,
browserHistory,
Switch
} from 'react-router-dom';
import App from './app/App';
import Welcome from './app/Welcome';
import NotFound from './app/NotFound';
const Root = () => (
<Router history={browserHistory}>
<Switch>
<Route exact path="/" component={App}/>
<Route path="/welcome" component={Welcome}/>
<Route component={NotFound}/>
</Switch>
</Router>
);
ReactDOM.render(
<Root/>,
document.getElementById('root')
);

With the new version of React Router (using 2.0.1 now), you can use an asterisk as a path to route all 'other paths'.
So it would look like this:
<Route route="/" component={App}>
<Route path=":area" component={Area}>
<Route path=":city" component={City} />
<Route path=":more-stuff" component={MoreStuff} />
</Route>
<Route path="*" component={NotFoundRoute} />
</Route>

This answer is for react-router-4.
You can wrap all the routes in Switch block, which functions just like the switch-case expression, and renders the component with the first matched route. eg)
<Switch>
<Route path="/" component={home}/>
<Route path="/home" component={home}/>
<Route component={GenericNotFound}/> {/* The Default not found component */}
</Switch>
When to use exact
Without exact:
<Route path='/home'
component = {Home} />
{/* This will also work for cases like https://<domain>/home/anyvalue. */}
With exact:
<Route exact path='/home'
component = {Home} />
{/*
This will NOT work for cases like https://<domain>/home/anyvalue.
Only for https://<url>/home and https://<domain>/home/
*/}
Now if you are accepting routing parameters, and if it turns out incorrect, you can handle it in the target component itself. eg)
<Route exact path='/user/:email'
render = { (props) => <ProfilePage {...props} user={this.state.user} />} />
Now in ProfilePage.js
if(this.props.match.params.email != desiredValue)
{
<Redirect to="/notFound" component = {GenericNotFound}/>
//Or you can show some other component here itself.
}
For more details you can go through this code:
App.js
ProfilePage.js

For those who are using react router v6
Redirect component has been removed from the react-router version 6.
For react-router-dom v6, simply replace Redirect with Navigate
Migrating up to v6
npm install react-router-dom#6
import {Routes, Route, Navigate } from "react-router-dom";
function App() {
return (
<div>
<Routes>
<Route path="/404" element={<div>Choose the correct path/div>} />
<Route path="*" element={<Navigate replace to="/404" />} />
</Routes>
</div>
);
}

According to the documentation, the route was found, even though the resource wasn't.
Note: This is not intended to be used for when a resource is not found. There is a difference between the router not finding a matched path and a valid URL that results in a resource not being found. The url courses/123 is a valid url and results in a matched route, therefore it was "found" as far as routing is concerned. Then, if we fetch some data and discover that the course 123 does not exist, we do not want to transition to a new route. Just like on the server, you go ahead and serve the url but render different UI (and use a different status code). You shouldn't ever try to transition to a NotFoundRoute.
So, you could always add a line in the Router.run() before React.render() to check if the resource is valid. Just pass a prop down to the component or override the Handler component with a custom one to display the NotFound view.

The above answers are correct and for react 5 before. In React v6, Switch no longer exists. This solution is for react v6:
import {BrowserRouter as Router, Routes, Route, Link} from "react-router-dom";
...
<Router>
<ul>
<li>
<Link to="t1">component1</Link>
</li>
<li>
<Link to="t2">component2</Link>
</li>
</ul>
<Routes>
<Route path="/t1" exact element={<Component1/>}/>
<Route path="/t2" exact element={<Component2/>}/>
<Route path="*" element={<NotFound/>}/>
</Routes>
</Router>

I just had a quick look at your example, but if i understood it the right way you're trying to add 404 routes to dynamic segments. I had the same issue a couple of days ago, found #458 and #1103 and ended up with a hand made check within the render function:
if (!place) return <NotFound />;
hope that helps!

React Router v6
Live Demo: Redirect Default or 404 Routes with React Router
Example code:
<Router>
<Routes>
<Route path="users" element={<Users />} />
<Route path="posts" element={<Posts />} />
</Routes>
</Router>
To redirect and navigate to one of our chosen routes, we can use <Navigate> component from React Router. Now we can declare below our route configuration the case for empty routes, like this:
<Router>
<Routes>
<Route path="users" element={<Users />} />
<Route path="posts" element={<Posts />} />
<Route path="" element={<Navigate to="/users" />} />
</Routes>
</Router>

I had similar issue, instead of using * wild identifier or Default Switch Component. We can simply just use Route Component without defining path.
example:
<Switch>
<Route path="/" component={Root} />
<Route path="/home" component={Home} />
<Route component={NotFoundPage} />
// Default Component To load If none of the path matches.
</Switch>

Related

What is wrong with the structure of my 'BrowserRouter', 'Routes' and 'Route' in my function App()?

I am attempting to follow a tutorial while learning React.JS and I am running into an issue because the tutorial is using an older version of React and I am stuck trying to figure out how to use BrowserRouter, Routes, and Route.
Can anyone assist me in trying to re-structure the code so it works with the updated version of React? I have tried reading through documentation and tried to mix around a few solutions with no success. Any help is much appreciated!
import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import "bootstrap/dist/css/bootstrap.min.css";
import Navbar from "./components/navbar.component.js";
import PortfolioList from "./components/portfolio-list.component";
import EditPortfolio from "./components/edit-portfolio.component";
import CreatePortfolio from "./components/create-portfolio.component";
import CreateUser from "./components/create-user.component";
function App() {
return (
<Routes>
<Navbar />
<br/>
<Route path="/" exact component={PortfolioList} />
<Route path="/edit/:id" exact component={EditPortfolio} />
<Route path="/create" exact component={CreatePortfolio} />
<Route path="/user" exact component={CreateUser} />
</Routes>
);
}
export default App;
The following is the 'error' I'm generating on runtime:
Error: [Navbar] is not a 'Route' component. All component children of
'Routes' must be a 'Route' or 'React.Fragment'
Only Route components and React.Fragments can be a child of the Routes component, and vice-versa. Move the non-Route components out of Routes. The Route component API also changed in version 6, there is no longer render and component props, the routed components are passed to the element prop as JSX, and routes are now always exactly matched, so there's no longer the exact prop as well.
function App() {
return (
<>
<Navbar />
<br/>
<Routes>
<Route path="/" element={<PortfolioList />} />
<Route path="/edit/:id" element={<EditPortfolio />} />
<Route path="/create" element={<CreatePortfolio />} />
<Route path="/user" element={<CreateUser />} />
</Routes>
</>
);
}
you can use the "BrowserRouter" tag followed by the "Switch" tag then you can now use the "Route" tag to specify the path of each component
you can use the "BrowserRouter" tag followed by the "Switch" tag then you can now use the "Route" tag to specify the path of each component.
return (
<>
<BrowserRouter>
<Switch>
<Route path="/" exact component={DashBoard} />
<Route path="/specialistes" exact component={Specialistes} />
<Route path="/findgarages" exact component={FindGarage} />
<Route path="/garages" exact component={Garages} />
</Switch>
</BrowserRouter>
</>
)````

React router order of routes, does it matter?

I set up my react router like this:
<Route exact path="/users">
<component/>
</Route>
<Route exact path="/users/:id">
<component/>
</Route>
And it wasn't working correctly (url was changing but content wasn't)
after I changed the order of Route in my Routes.js (the one with :id first) it started working. Do it matters or there is other problem somewhere in my code?
Yes you need to check
Route and
Switch
<Switch> is unique in that it renders a route exclusively. In contrast, every <Route> that matches the location renders inclusively.
Read and explore more at https://reactrouter.com/web/api/Switch
Yes, nested routes should be above its parent.
So in the following code, about/user has to be above /about. If its beneath then only /about will render
<Route path='about/user' />
<Router path='about/' />
Basic React Router Setup
<Router>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>

React routing - NotFound component does not load in all cases

I am a beginner in reactJS. I have the following routes defined in App.js
<Router>
<Switch>
<Route exact path='/' component={Login} />
<Route path='/dashboard' component={Dashboard} />
<Route path="*" component={NotFound} ></Route>
</Switch>
</Router>
The NotFound component should be displayed for any invalid route. It works perfectly for all invalid route that looks like this
localhost:3000/something_invalid
localhost:3000/something_invalid_1
but if I add one more step to the URL. The NotFound component is not getting rendered. e.g.,
localhost:3000/something_invalid/something_invalid
localhost:3000/something_invalid_1/something_invalid_1
What could I be doing wrong ?
<Router>
<Switch>
<Route exact path='/' component={Login} />
<Route path='/dashboard' component={Dashboard} />
<Route component={NotFound} ></Route>
</Switch>
</Router>
Code updated.
A 'Switch' renders the first child 'Route' that matches. A 'Route' without a path always matches.
The asterisk in your example is used in React-Router until version 3.
If you use the root URL, it'll work as a catch all
Note that this works because it comes after your other defined routes, ie. /dashboard still works
<Router>
<Switch>
<Route exact path='/' component={Login} />
<Route path='/dashboard' component={Dashboard} />
<Route path="/" component={NotFound} ></Route>
</Switch>
</Router>

react routing issues when routes other that in routing config are hit

I am building a web app with different routes.
There is this case where if a user hits any arbitrary route then he gets directed to Login Component. But it only handles case where bad routing happens this way localhost:3000/gvgdvgdvgd.
I have routes such as /home/news. A user may end up hitting /home/news/10 manually which doesn't exist. Similarly there is a route such as coupon and user may end up hitting /coupons/88 without going to coupons first.
How do I handle these issues in my web-app? I handled it for the first case. Here is the routing config.
<Route path="/login" component={LoginLoadable} />
<Route path="/home" component={Home} />
<Route path="/maths" component={Maths} />
<Route
exact
path="/"
render={routeProps => (
<Component1
{...routeProps}
/>
)}
/>
<Route component={LoginLoadable}/>
What about the case where user hits maths/123/1ydhd manually when that doesn't exist?
Wrap your routes in a Switch and add a Route with no path prop that renders your 404 page. If you don't specify a path, it should always render that route. Adding a Switch makes sure only one route will render. Also you will need to add the exact prop to your routes. See:
https://reacttraining.com/react-router/web/api/Route/exact-bool for how it matches sub-routes.
Something like:
<Switch>
<Route path="/login" component={LoginLoadable} />
<Route exact path="/home" component={Home} />
<Route exact path="/maths" component={Maths} />
<Route
exact
path="/"
render={routeProps => (
<Component1
{...routeProps}
/>
)}
/>
<Route component={LoginLoadable}/> // <-- remove this since you render it in '/login'
<Route component={A404Page} // <-- add this
</Switch>

React Router - Stay at the same page after refresh

I'm learning React. I have page with 4 subpages and i use React Router to go through those pages. Everything works fine except for reloading page. When i go from page "home" to "about" or other it's ok, but when i refresh page then it render again page "about" for a second and then it change page to home (home is default/first page).I want it to stay at that page which is currently rendered, not go back to home after every refresh.
There is my code in index.js file where i render whole app and use router:
<Provider store={store}>
<Router path="/" history={browserHistory}>
<Route path="/home" component={App}>
<Route path="/" component={Home}/>
<Route path="/allhotels" component={AllHotels}/>
<Route path="/addhotel" component={AddHotel} />
<Route path="/about" component={About} />
</Route>
<Route path="/signin" component={SignIn} />
<Route path="/signup" component={SignUp} />
</Router>
</Provider>, document.getElementById('root')
In "App" i have Navigation and there i render rest of conent from Home, AllHotels etc.
There is code from App.jsx
class App extends Component {
render() {
return (
<div className="app-comp">
<Navigation />
<div> {this.props.children}</div>
</div>
)
}
}
I also attach gif which shows my problem.
https://gifyu.com/image/boMp
In backend i use Firebase if it's important.
Thanks in advance.
I found the reason of my problem. I use also Firebase in my project and it causes the problem.
Thanks guys for help.
EDIT ======================================================================
Mabye I will write how I've fixed my problem and what was the reason of it.
So i was checking if user is logged in or not in auth method. And there if user was authorized I was pushing / to browserHistory.
It was mistake because every refresh method was executing and then also redirection was called as well.
Solution is just to check if during executing auth method I'm on Signin page or not. If it is Signin page then I'm pushing / to browserHistory but if not then just don't push anything.
firebaseApp.auth().onAuthStateChanged(user => {
if (user) {
let currentPathname = browserHistory.getCurrentLocation().pathname;
if( currentPathname === "/" || currentPathname === "/signin"){
browserHistory.push('/');
}
const { email } = user;
store.dispatch(logUser(email));
}
else {
browserHistory.replace('/signin');
}
})
I know that it's not pretty solution but it works and it was only home project which was created to learn react. (btw this project is using old react router 3.0 so probalby now using browserHistory is deprecated)
Check that firebase does not interfares with the client side routes :P
You can use Index routes to achieve this.
You have your navigation i.e the layout of all pages in your app component so make it the root route.
Then you want your home route to be your default route so make it your Index route.
You need to import IndexRoute from react-router package (from which you import Route).
Add this-
import { Router, Route, IndexRoute } from 'react-router';
and then make your routes like below.
Use this-
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="/home" component={Home}/>
<Route path="/allhotels" component={AllHotels}/>
<Route path="/addhotel" component={AddHotel} />
<Route path="/about" component={About} />
</Route>
<Route path="/signin" component={SignIn} />
<Route path="/signup" component={SignUp} />
</Router>
</Provider>, document.getElementById('root')
it's a Server-side vs Client-side issue
check the following thread, it might give you some insights.. React-router urls don't work when refreshing or writting manually
Below example you can refer for :
React Router Navigation
Browser Refresh Issue.
Browser Back Button Issue.
Please make sure you have installed react-router-dom
If not installed. Use this command to install npm i react-router-dom
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Page1 from "./Page1";
import Page2 from "./Page2";
const rootElement = document.getElementById("root");
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route exact path="/" component={Page1} />
<Route path="/page2" component={Page2} />
</Switch>
</BrowserRouter>,
rootElement
);
Page1.js
import React from "react";
import {Link } from "react-router-dom";
function Page1() {
return (
<div>
<p>
This is the first page.
<br />
Click on the button below.
</p>
<Link to="/page2"><button>
Go to Page 2
</button>
</Link>
</div>
);
}
export default Page1;
Page2.js
import React from "react";
function Page2() {
return (
<div>
<p>This is the second page.</p>
</div>
);
}
export default Page2;
Add into your webpack.config.js this option
devServer: {
historyApiFallback: true
},
Route tag returns the first matching component.
I think you have interchanged the paths of home and app component.
try this.
<Provider store={store}>
<Router path="/" history={browserHistory}>
<Route path="/" component={App}>
<Route path="/home" component={Home}/>
<Route path="/allhotels" component={AllHotels}/>
<Route path="/addhotel" component={AddHotel} />
<Route path="/about" component={About} />
</Route>
<Route path="/signin" component={SignIn} />
<Route path="/signup" component={SignUp} />
</Router>
</Provider>, document.getElementById('root')

Categories

Resources