React-Router: No Not Found Route?

JavascriptReactjsReact Router

Javascript Problem Overview


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

Javascript Solutions


Solution 1 - Javascript

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!

Solution 2 - Javascript

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')
);

Solution 3 - Javascript

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>

Solution 4 - Javascript

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

Solution 5 - Javascript

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>
    );
}

Solution 6 - Javascript

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.

Solution 7 - Javascript

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!

Solution 8 - Javascript

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>

Solution 9 - Javascript

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>

Solution 10 - Javascript

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>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Question4m1rView Question on Stackoverflow
Solution 1 - JavascriptJanne AnnalaView Answer on Stackoverflow
Solution 2 - JavascriptmetakermitView Answer on Stackoverflow
Solution 3 - JavascriptdejakobView Answer on Stackoverflow
Solution 4 - JavascriptPransh TiwariView Answer on Stackoverflow
Solution 5 - JavascriptVishal RanaView Answer on Stackoverflow
Solution 6 - JavascriptBradByteView Answer on Stackoverflow
Solution 7 - JavascriptJörnView Answer on Stackoverflow
Solution 8 - JavascriptParisaNView Answer on Stackoverflow
Solution 9 - JavascriptChilaxathorView Answer on Stackoverflow
Solution 10 - JavascriptSiddharth SunchuView Answer on Stackoverflow