Lang
Blog

Wouter — A Minimalist 1.2kb Alternative to React Router

ByPayal Mittal
October 20th . 5 min read
Wouter — A Minimalist 1.2kb Alternative to React Router

At present, React Router is the most popular routing solution for React applications. It is a complete routing package enriched with a long list of features.

However, there are many features in React Router that become irrelevant if you are building smaller applications. Let’s say you’re building an application that needs browser-based routing which leaves no room for features like memory routing and hash-based routing.

Thus, came into role the new Wouter.

The whole idea behind Wouter is that when a developer chooses to work with React Router, he utilizes only its 30 to 40% features. Wouter acts as a smaller alternative to React Router packed only with these handfuls of features that are commonly used.

Wouter is a minimalistic form of React Router and contains only the most commonly used functionalities.

In this blog, we will learn more about Wouter, its features, APIs, and much more-

What is Wouter?

Wouter is a tiny and minimalist-friendly router library for modern React and Preact apps that relies on Hooks.

Wouter provides simple and intuitive APIs that many developers and library authors appreciate. Some notable projects that use Wouter: Arcade, react-three-fiber, ssgl-doom-launcher, Ziro App and many more.

Whatever you could do with react-router you can achieve with Wouter too. Here are some features that makes Wouter preferable over React Router-

  • Zero Dependencies- gzipped to 1308 bytes in compared to 11 kb of React Router.
  • In addition to React, Wouter also supports the alternative to React- Preact (through wouter-preact package)
  • The <Router /> component is completely optional in Wouter.
  • Wouter has hooks API, rendering more control over routing.
  • Follows the best practices of React Router by providing familiar components like Route, Switch, Link and Redirect.
  • Obsolete platform support

Along with these advantages, there are some downfalls as well, such as -

  • It doesn’t support React Native.
  • No support for HashRouter or MemoryRouter.

Getting Started with Wouter

The very first step towards using Wouter is to install its package either from npm or yarn package manager, whichever you prefer -

npm install wouter
or
yarn add wouter

Now, to setup and implement Wouter, you will need to import <Link/> and <Route/> components. You can take help from this demo code -

import { Link, Route } from "wouter";
const App = () => (
  <div>
    <Link href="/users/Zedd">
      <a className="link">Profile</a>
    </Link>
    <Route path="/inbox” component={InboxPage} />
    <Route path="/about">About Us</Route>
    <Route path="/users/:name">
      {(params) => <div>Hello, {params.name}!</div>}
    </Route>
  </div>
);
export default App:

Wouter APIs

Wouter brings two types of APIs: React Hooks API and traditional component API. You can choose either one of them based upon your requirements.

While Hooks APIs might come in handy if you want to create custom routing components or building smaller applications, the component API will be preferred in case you’re building traditional application with navigation and pages.

Hooks API -

Wouter uses react hooks which makes the custom interactions like route transition or accessing easier. It consists of 3 hooks that are easier to use and are explained below-

  • The first hook is useRoute hook which is used to determine whether or not the particular route matches the provided path:
import { useRoute } from "wouter";
import { Transition } from "react-transition-group";
const AnimatedRoute = () => {
  const [match, params] = useRoute("/users/:id");
  return <Transition in={match}>Hi, this is: {params.id </Transition>;
};
  • The second hook is useLocation hook which is used for low-level navigation. It acts as a wrapper around the native browser location object API so that when the location changes, it rerenders and performs the navigation.
import { useLocation } from "wouter";
const CurrentLocation = () => {
  const [location, setLocation] = useLocation();
  return (
    <div>
      {`The current page is: ${location}`}
      <a onClick={() => setLocation("/somewhere")}>Click to update</a>
    </div>
  );
};
  • The last one is useRouter hook which holds the custom location hook function and matcher function and returns a global router object. It can be used while using a top-level router component. It also acts as a mediator object to store arbitrary data -
import { useRouter } from "wouter";
import useLocation from "wouter/use-location";
const Custom = () => {
  const router = useRouter();
  router.lastTransition = { path: "..." };
};

Now, let’s move to another type of Wouter API, i.e. component API-

Component API -

The main Wouter components are described as given here -

- <Route/>

The <Route /> component conditionally renders an app component when the current path matches with a specific pattern. The pattern is a string which might contain special characters that represent dynamic segments.

Here are given the ways in which a route’s body can be declared -

import { Route } from "wouter";
// simple form
<Route path="/home"><Home /></Route>
// render-prop style
<Route path="/users/:id">
  {params => <UserPage id={params.id} />}
</Route>
// the `params` prop will be passed down to <Orders />
<Route path="/orders/:status" component={Orders} />
  • <Link/>

The <Link> component renders an anchor element <a> that enables us to navigate the route specified in the href prop. You can also customize it by adding your own <a> element or by linking it as a children element-

import { Link } from "wouter";
// All of these will produce the same html:
// <a href="/foo" class="active">Hello!</a>
<Link href="/foo" className="active">Hello!</Link>
<Link href="/foo"><a className="active">Hello!</a></Link>
<Link href="/foo"><A>Hello!</A></Link>
  • <Switch/>

the <Switch> component is used in the cases of exclusive routing, where only one route is preferred and rendered at a time and all the other routes are ignored. It only renders the first matching route.

import { Route, Switch } from "wouter";
<Switch>
  <Route path="/orders/all" component={AllOrders} />
  <Route path="/orders/:status" component={Orders} />
</Switch>;
  • <Redirect/>

The <Redirect/> component, as the name implies, redirects the user to another path provided in the to prop. It makes use of useLocation hook to trigger the navigation internally inside the useEffect block.

import { Redirect } from "wouter";
const User = ({ userId }) => {
  if (!userId) return <Redirect to="/login" />;
return <div> Current User is {userId} </div>;
};

Or, you can directly access the setLocation method for navigation by using useLocation hook.

import { useLocation } from "wouter";
const [location, setLocation] = useLocation();
fetchOrders().then((orders) => {
  setOrders(orders);
  setLocation("/app/orders");
});

Wouter for Server-side Rendering (SSR)

Yes! Wouter provides support for server-side rendering. Isn’t it amazing?

Well, to use Wouter for SSR, you need to instruct the router that the current location must come from the HTTP request and not from the browser history.

For Wouter to handle these HTTP requests, you can replace the default useLocation hook by staticLocationHook.

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

Making a Default Route

In application routing, having a default route is quite common and is used as a fallback in the cases where no other route matches. For instance, whenever there is 404 error, a default route is used to render the ‘404, Not Found’ error message.

The same thing is done in Wouter also. All you have to do is to combine a default route to a <Switch /> component, as shown below-

import { Switch, Route } from "wouter";
<Switch>
  <Route path="/about">...</Route>
  <Route>404, Not Found!</Route>
</Switch>;

Reducing the Bundle Size with Wouter

If you favor small bundle-size and need to use routing in your app, you can use the useLocation hook which is only 341 bytes gzipped. Through this hook, you can reduce your app bundle size further.

import useLocation from "wouter/use-location";
const UsersRoute = () => {
  const [location] = useLocation();
  if (location !== "/users") return null;
  // render the route
};

For more details, refer to this documentation link -

Documentation

Summary:

Although, Wouter is a wonderful routing solution in some cases, it cannot replace React Router. Also, you cannot switch your project to Wouter because it does not cover all the features of eact Router thus, this kind of migration will not work in most cases.

However, it is a great choice of routing solution for smaller projects where one needs some basic routing.

You might hit some claps, if you liked this blog 😉. Keep reading until the next time I come with a new blog.

Happy Reading!!

Share:
0
+0