DEV Community

Cover image for Migrating from react-router to wouter
Aleksei Berezkin
Aleksei Berezkin

Posted on

Migrating from react-router to wouter

Artwork: https://code-art.pictures/

Why migrate to wouter?

react-router adds about 30 kB (minified) to your bundle, while wouter requires less than 4 kB. Although the react-router team has made significant efforts in version 7 to optimize its bundle size, it still feels excessive if your primary task is simply switching between a few routes.

Moreover, implementing server-side rendering (SSR) with wouter is straightforward. In contrast, with react-router v7, SSR is only easy when you use it as a framework. If you prefer to use it as a library, the process is unclear since it's not documented — an omission that's both surprising and frustrating, to be honest.

Why stay with react-router?

react-router is a mature library with a large and active community. If your project involves complex routing scenarios, react-router is more likely to provide the tools and support you need.

Hint: If you decide to stick with react-router, be sure to upgrade from v6. Version 7 is about twice as efficient in terms of bundle size.

1. Updating deps to wouter

npm uninstall react-router react-router-dom
npm i wouter
Enter fullscreen mode Exit fullscreen mode

If you're already on react-router v7, you probably don't have react-router-dom.

2. Updating Routes to Switch

  • Update imports
  • Change <Routes> to <Switch>
  • In your routes, move elements from element property to <Route>'s children

Before

import { BrowserRouter, Route, Routes } from 'react-router'

function App() {
  return (
    <Routes>
      <Route path='/' element={<Index/>} />
      ...
    </Routes>
  )
}
Enter fullscreen mode Exit fullscreen mode

After

import { Route, Switch } from 'wouter'

function App() {
  return (
    <Switch>
      <Route path='/'>
        <Index/>
      </Route>
      ...
    </Switch>
  )
}
Enter fullscreen mode Exit fullscreen mode

3. Updating Links

Just update imports. wouter has the same API here

Before

import { Link } from 'react-router'
Enter fullscreen mode Exit fullscreen mode

After

import { Link } from 'wouter'
Enter fullscreen mode Exit fullscreen mode

4. Updating navigation

  • Update imports
  • Change useNavigate() to useLocation()
  • Change navigate() to setLocation()

Before

import { useNavigate } from 'react-router'

function MyComponent() {
  const navigate = useNavigate()

  function navToAbout() {
    navigate('/about')
  }

  // ...
}
Enter fullscreen mode Exit fullscreen mode

After

import { useLocation } from 'wouter'

function MyComponent() {
  const [, setLocation] = useLocation()

  function navToAbout() {
    setLocation('/about')
  }

  // ...
}
Enter fullscreen mode Exit fullscreen mode

5. Implementing SSR

I don’t know how to implement SSR with react-router v7 🙂 That’s why, in this step, we’ll implement it from scratch using wouter — it’s surprisingly simple. All you need to do is wrap your app in a <Router> component:

entry-server.js

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

function prerenderApp() {
  return renderToString(
    <Router ssrPath='/'>
      <App />
    </Router>
  )
}
Enter fullscreen mode Exit fullscreen mode

entry-client.js

import { hydrateRoot } from 'react-dom/client'
import { Router } from 'wouter'

hydrateRoot(
  document.getElementById('app-root'),
  <Router>
    <App />
  </Router>
)
Enter fullscreen mode Exit fullscreen mode

We are done!

Now run your favorite bundle analyzer (e.g., webpack-bundle-analyzer or vite-bundle-visualizer) and enjoy the results!

Top comments (0)