DEV Community

Paramanantham Harrison
Paramanantham Harrison

Posted on • Originally published at learnwithparam.com

Creating 404 page in react using React Router

We have learned how to create dynamic URL in react router and also we learned how to handle query params in react router and pass those values to the page component in our previous posts.

In this part, we will learn how to show a 404 page if there is no route matching the URL.

You can find the last part and the latest codebase with codesandbox here

Run the application and visit any non-existing route, for example /404-not-found

Currently, you wouldn't see any page component rendered. Let's handle it and show a default page if there is no route which matches the path.

It's fairly simple to achieve in react router. Inside react router component, create a route without path defined. And make sure to place the code at the bottom of all routes, so that router will check all the routes and fallback if no match found.

// App.js

...

const NoMatchPage = () => {
  return (
    <h3>404 - Not found</h3>
  );
};

const App = () => {
  return (
    <section className="App">
      <Router>
        ...
        <Link to="/users">Users</Link>
        <Link to="/search?q=react">Search</Link>
        ...
        <Route exact path="/about" component={AboutPage} />
        <Route exact path="/search" component={SearchPage} />
        <Route component={NoMatchPage} />
      </Router>
    </section>
  );
};

...
Enter fullscreen mode Exit fullscreen mode

Visit any random URL, you will see a simple 404 page. But wait, let's check whether other pages work normally without breaking. It won't!

Check on about link, you will see both about and 404 page get rendered. Because first router matched the exact route for /about path and then it traverses to the bottom and load the 404 route since this route have no path defined.

React router provide a component called Switch to break once a route get resolved and not load any other route component below it.

Its fairly easy to implement. Enclose all the route inside Switch component. lets do it and make the 404 page works without error.

// App.js

...
import { Link, BrowserRouter as Router, Route, Switch } from 'react-router-dom';
...

const App = () => {
  return (
    <section className="App">
      <Router>
        ...
        <Switch>
          <Route exact path="/" component={IndexPage} />
          ...
          <Route exact path="/search" component={SearchPage} />
          <Route component={NoMatchPage} />
        </Switch>
      </Router>
    </section>
  );
};

...

Enter fullscreen mode Exit fullscreen mode

This Switch component will check for the matching route, if a route is already matched, it breaks checking the next routes. By this way, we will avoid rendering 404 route for all pages.

That's it folks, Hope you learned a trick of creating 404 page for your react app using react router 🤗

You can checkout the codebase for this series here and the code for this section here

Stay in touch!

If you enjoyed this post, you can find me on Twitter for updates, announcements, and news. 🐤

Top comments (11)

Collapse
 
tonixtuft profile image
Anton Bagdatyev (Tonix-Tuft)

How can you return a 404 status code with this SPA approach? If a URL does not effectively exists, a 404 would be more semantically correct than a 200 response code. Is there a way to achieve this somehow while using SPA?

Collapse
 
learnwithparam profile image
Paramanantham Harrison

Unless you sever rendered 404 page, it’s not possible
Will surely research more into the details on how to do it in SPA

Collapse
 
tonixtuft profile image
Anton Bagdatyev (Tonix-Tuft)

Thank you for your reply. I will too!

Collapse
 
gypsydave5 profile image
David Wickes

Pedantic question: if a server is not returning a Status Code of 404… is it still a 404 page?

Collapse
 
learnwithparam profile image
Paramanantham Harrison

No, it’s a not found page in client side route technically. It’s status code is going to be 200 since server will just route the index file and client handle the exact route.
It’s just the naming convention used by me as 404 page, it’s a not found page.

Collapse
 
jamesthomson profile image
James Thomson

Perhaps you could call it a "soft 404" whereas a servers response would be a "hard 404"?

Collapse
 
gypsydave5 profile image
David Wickes • Edited

This is really interesting to me. An artifact of the transport layer (the HTTP status code) has made it into the application layer. We're expecting the SPA to 'act' like a web browser, showing a 404 from a server when a resource (URL) is not found.

But it's not a web browser; it's a self contained JavaScript application. The artifact is actually from a completely different architectural model. Are we adding to the confusion if we start calling this error state a 404?

(I'm not trying to say there's a right way or a wrong way - I'm just trying to point out how weird this is when you think about it).

Collapse
 
learnwithparam profile image
Paramanantham Harrison

Yes that’s right. It’s a soft 404 in client side

Collapse
 
vincevegas profile image
vince vegas • Edited

Why the 404 page appearing to blog & contact router?

<BrowserRouter>

<Switch>
  <Route exact path="/" component={Home} />
  <Route exact path="/about" component={About} />
  <Route component={NotFoundPage} />
</Switch>

<Switch>
  <Route exact path="/blog" component={Blog} />
  <Route exact path="/contact" component={Contact} />
</Switch>

</BrowserRouter>
Collapse
 
learnwithparam profile image
Paramanantham Harrison

Because you have two switch statement, the router checks the first switch and loads the default not found route

Collapse
 
vincevegas profile image
vince vegas • Edited

Also this, why the Blog & Contact doesn't appear, is there any way to have multiple providers in Routes

 <Switch>
  <AProvider>
        <Route exact path="/" component={Home} />
        <Route exact path="/about" component={About} />
  </AProvider>

   <BProvider>
        <Route exact path="/blog" component={Blog} />
        <Route exact path="/contact" component={Contact} />
        <Route component={NotPage} />
    </BProvider>
</Switch>