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.
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.
Below you will find all the features or advantages that Wouter has to offer over React Router.
<Router />
component is entirely optional in 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;
<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> ); };
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.
import { useRoute, Link } from "wouter"; const CustomLink = (props) => { const [isActive] = useRoute(props.href); return ( <Link {...props}> <a className={isActive ? "active" : ""}>{props.children}</a> </Link> ); };
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 } };
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 };
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.
A few of the Pros and Cons of Wouter compared to the React Router library are listed below.
/app/:foo(\d+)
) are not yet developed)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.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowReact Native’s New Architecture offers significant performance advantages. In this article, you’ll explore synchronous and asynchronous rendering in React Native through practical use cases.
Build scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
2 Replies to "An introduction to Wouter: A React Router alternative"
Well this will be a confusing package for me.
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”