Skip to content

React Router errorReact Router: “Attempted import error: 'Switch' is not exported from 'react-router-dom'”

The build fails with Switch is not exported from react-router-dom (webpack says export 'Switch' (imported as 'Switch') was not found in 'react-router-dom'; Vite says it does not provide an export named Switch), or the same error for useHistory, Redirect or withRouter. The project installed React Router v6 or later, but the code, a tutorial or a generated component uses the v5 API. v6 renamed or removed those exports.

Short answer

Rename to the v6 API: Switch becomes Routes, useHistory becomes useNavigate, Redirect becomes Navigate, and component={Page} becomes element={<Page />}. Check the version with npm ls react-router-dom. If you need the app running today and the codebase is large, pin react-router-dom@5 as a stopgap, or use the react-router-dom-v5-compat package to migrate route by route.

Which v5 name you used, and the v6 replacement

  1. 01

    Switch: use Routes, and element instead of component

    “React Router v6 introduces a Routes component that is kind of like Switch, but a lot more powerful.” React Router, Upgrading from v5

    Wrap routes in Routes. Each Route takes element with JSX, not component or render, and exact is gone because v6 picks the best match. Routes are chosen based on the best match instead of being traversed in order, so the order of your routes no longer decides which one renders.

    // v5
    <Switch>
      <Route exact path="/" component={Home} />
      <Route path="/users/:id" component={User} />
    </Switch>
    
    // v6
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/users/:id" element={<User />} />
    </Routes>
  2. 02

    useHistory: use useNavigate

    “Most of the time this means changing useHistory to useNavigate and changing the history.push or history.replace callsite.” React Router, Upgrading from v5

    useNavigate returns a function. history.push('/home') becomes navigate('/home'), and history.replace('/home') becomes navigate('/home', { replace: true }).

    import { useNavigate } from 'react-router-dom';
    
    function SaveButton() {
      const navigate = useNavigate();
      return <button onClick={() => navigate('/done')}>Save</button>;
    }
  3. 03

    Redirect: use Navigate

    A redirect route becomes a Route whose element is <Navigate to="/new" replace />. A private route wrapper returns <Navigate to="/login" /> when the user isn’t signed in, and is used as an element, not as a custom child of Routes.

    <Route path="/old" element={<Navigate to="/new" replace />} />
  4. 04

    withRouter and class components

    withRouter was removed. In a function component, use useNavigate, useParams and useLocation. For a class component, write a small wrapper function component that calls those hooks and passes the values down as props. Other renames come up next: useRouteMatch becomes useMatch, NavLink activeClassName becomes a className function, Prompt was removed, and a parent route with child routes needs path="/users/*" or an <Outlet />. useNavigate() may be used only in the context of a <Router> means the component renders outside BrowserRouter.

Checked against the vendor’s docs on : React Router: Upgrading from v5.

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

Related: React “Element type is invalid” · Page not found on refresh (Netlify, Vercel) · React “Invalid hook call”

Questions

More on this error

Should I just downgrade to v5?

Only as a stopgap. npm install react-router-dom@5 gets an old app building again, but v5 gets no new features. Migrate to the current version when you can; the upgrade guide covers each rename.

Does this apply to React Router v7?

Yes. v7 keeps the v6 names (Routes, useNavigate, Navigate), so v5 code fails the same way. In v7 the main package is react-router; react-router-dom still works as a re-export.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.