Gaurav Singhal Gaurav is a data scientist with a strong background in computer science and mathematics. As a developer, he works with Python, Java, Django, HTML, Struts, Hibernate, Vaadin, web scraping, Angular, and React.

An introduction to Wouter: A React Router alternative

5 min read 1549

The React logo.

The JavaScript ecosystem is always in a constant state of flux. Despite the changes, the JavaScript community strives to resolve all issues as they crop up. If you have worked with React before, you will notice that the go-to routing solution is the React Router library.

It’s often wrongly portrayed as the official routing solution from Facebook. In reality, though, most of the projects at Facebook do not even utilize it.

The majority of the web app projects and use cases can do pretty well with a small and straightforward routing library.

One such routing solution is Wouter. In this guide, you will get an overview of Wouter and see how it can be implemented in place of React Router.

How does client side routing work?

Client side routing (CSR) is similar to server side routing (SSR), except CSR is handled by the browser. In a typical web app, some several pages or routes map into different URLs. Each page has some logic and a template that is then rendered once the route is called.

CSR is handled entirely by the browser’s JavaScript engine. Client side frameworks prefetch and load the JavaScript bundle. This enables the app to switch between pages stored in the bundle without losing the state or app data.

Frontend routing or CSR works by matching the URL with the login from the JavaScript file and then fetching the necessary data from the server using an API.

To learn more about client side routing, you can refer to this guide where CSR is explained in more detail.

Wouter features

Below you will find all the features or advantages that Wouter has to offer over React Router.

  • It has zero dependencies — only 1308 bytes gzipped compared to React Router’s 17KB.
  • Along with React, Wouter also supports Preact, which is a tiny alternative to React with the same API.
  • The <Router /> component is entirely optional in Wouter.
  • Wouter is a Hook-based API, so you have more control over routing.

Getting started with Wouter

Take a look at this basic code for setting up routing using Wouter. All you need to do is import the Link and Route components from wouter, and you are good to go. This setup is very minimal compared to all the boilerplate required by react-router.

import { Link, Route } from "wouter";

const App = () => (
  <div>
    <Link href="/users/John">
      <a className="link">My Account</a>
    </Link>

    <Route path="/inbox" component={InboxPage} />
    <Route path="/settings">Settings</Route>
    <Route path="/users/:name">
      {(params) => <div>Hello, {params.name}!</div>}
    </Route>
  </div>
);

export default App;

Wouter components

<Route />

The <Route /> component represents a part of the app that is rendered conditionally based on a specific pattern. The pattern is a string that can contain special characters to match dynamic segments.



Wouter provides different ways to declare a route.

import { Route } from "wouter";

// basic usage
<Route path="/home"><Home /></Route>

// render-prop style usage
<Route path="/profile/:id">
  {params => <ProfilePage id={params.id} />}
</Route>

// prop based usage
<Route path="/orders/:status" component={Orders} />

<Link />

The <Link /> component renders an anchor <a /> element that on click navigates to the route specified in the href prop. It can also be customized by providing a custom component as its children.

import { Link } from "wouter";

<Link href="/users/all" className="active">
  List Users
</Link>;

<Link href="/users/all">
  <CustomLink> List Users </CustomLink>
</Link>;

<Switch />

There may be cases where you would want exclusive routing. That is, only one route needs to be rendered on the page at all times, even if the routes have a pattern that overlaps with each other.

You can achieve exclusive routing using the <Switch /> component. It only renders the first matching route.

import { Route, Switch } from "wouter";

<Switch>
  <Route path="/users/all" component={AllUsers} />
  <Route path="/users/:userId" component={User} />
</Switch>;

Redirect

The <Redirect /> component is used to redirect the user to another route provided in the to prop. It uses the useLocation Hook internally to trigger the navigation inside of the useEffect callback block.

import { Redirect } from "wouter";

const User = ({ userId }) => {
  if (!userId) return <Redirect to="/login" />;

  return <div> Current User is {userId} </div>;
};

To programmatically navigate the user, you can directly access the setLocation method using the useLocation Hook.

import { useLocation } from "wouter";

const App = () => {
  const [location, setLocation] = useLocation();

  const navigate = () => {
    setLocation("/login");
  };

  return (
    <div>
      <button onClick={() => navigate()}> Logout </button>
    </div>
  );
};

How to make the current link active

Determining if a link is currently active or not, for example, in the navigation menu, is not supported by Wouter out-of-the-box. However, this functionality can be easily implemented by creating a wrapper component and detecting if the current path is active using the useRoute Hook.


More great articles from LogRocket:


import { useRoute, Link } from "wouter";

const CustomLink = (props) => {
  const [isActive] = useRoute(props.href);

  return (
    <Link {...props}>
      <a className={isActive ? "active" : ""}>{props.children}</a>
    </Link>
  );
};

Using Wouter for server side rendering (SSR)

To use Wouter in a server side context, you will need to instruct the router that the current location needs to come from the HTTP request rather than the browser history.

You can use staticLocationHook instead of the default useLocation Hook to tell the router to handle incoming HTTP requests.

import { renderToString } from "react-dom/server";
import { Router } from "wouter";

import staticLocationHook from "wouter/static-location";

import App from "./App";

const handleRequest = (req, res) => {
  const prerendered = renderToString(
    <Router hook={staticLocationHook(req.path)}>
      <App />
    </Router>
  );

  // return with prerendered html
};

If you need to detect redirects, you can also provide the record option to the staticLocationHook. The location.history property is an array matching the user’s history that would be captured after loading the page.

import { renderToString } from "react-dom/server";
import { Router } from "wouter";
import staticLocationHook from "wouter/static-location";

import App from "./App";

const handleRequest = (req, res) => {
  const location = staticLocationHook(req.path, { record: true });
  const prerendered = renderToString(
    <Router hook={location}>
      <App />
    </Router>
  );

  const finalPage = location.history.slice(-1)[0];
  if (finalPage !== req.path) {
    // perform redirect here
  }
};

Minimize the bundle size further

If you are a bundle size minimalist and want to keep your app’s bundle size as small as possible, you can have all the routes handled using the useLocation Hook.

The useLocation Hook is a low-level navigation API that powers the core Wouter components and routing. It is essentially a wrapper around the native browser location object.

import { useLocation } from "wouter";

const CurrentLocation = () => {
  const [location, setLocation] = useLocation();

  return (
    <div>
      {`The active page is: ${location}`}
      <button onClick={() => setLocation("/users")}>
        Click to update the route
      </buttom>
    </div>
  );
};

The useLocation Hook can also be accessed from a separate file, which will decrease the bundle size further down if you are only going to use the useLocation Hook and match the routes manually.

import useLocation from "wouter/use-location";

const UsersRoute = () => {
  const [location] = useLocation();

  if (location !== "/users") return null;

  // render the route
};

Obsolete platform support

The Wouter library uses the latest EcmaScript (ES) 6 features like destructuring assignment and const/let variable declarations, and does not come with ES5 transpiled source code. If you want to support legacy browsers like Internet Explorer 11 and below, make sure you run Babel over the node_modules folder.

Pros and cons compared to React Router

A few of the Pros and Cons of Wouter compared to the React Router library are listed below.

Pros:

  • Wouter is tiny and has no dependencies on other libraries
  • Wouter is excellent for side projects, hackathon projects, and small apps with around ten routes
  • Wouter can be a good inspiration for developers who want to learn more about React Hooks by reading source code

Cons:

  • Wouter only implements a limited set of functionalities (redirects, switches, support for hash-based history, extended pattern syntax (like /app/:foo(\d+)) are not yet developed)
  • Not a good option for complex and enterprise-level apps
  • The community behind Wouter is much smaller compared to React Router

Conclusion

Wouter is undoubtedly not a replacement for React Router, and nor it is recommended switching over to Wouter in your project. Migration from React Router to Wouter would not work in most use cases because Wouter only mimics and doesn’t fully implement the features of the React Router API.

But the main idea behind Wouter is that most developers tend to choose React Router and then use only 30% of functionality or features. React Router can be overkill for a basic side project where only simple routing is required.

Wouter can also be used as a reference to how React Hooks can be used to create excellent libraries that can be open-sourced.

So that’s it for this guide. Until next time, keep exploring more routing solutions and libraries.

References

 

LogRocket: Full visibility into your production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket combines session replay, product analytics, and error tracking – empowering software teams to create the ideal web and mobile product experience. What does that mean for you?

Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay problems as if they happened in your own browser to quickly understand what went wrong.

No more noisy alerting. Smart error tracking lets you triage and categorize issues, then learns from this. Get notified of impactful user issues, not false positives. Less alerts, way more useful signal.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Gaurav Singhal Gaurav is a data scientist with a strong background in computer science and mathematics. As a developer, he works with Python, Java, Django, HTML, Struts, Hibernate, Vaadin, web scraping, Angular, and React.

2 Replies to “An introduction to Wouter: A React Router alternative”

  1. Great article! But nothing in it supports the conclusion that:

    “Wouter is excellent for […] small apps with around ten routes” / “Not a good option for complex and enterprise-level apps”

Leave a Reply