35

im using react router v6 and i every time i use initializing for authentication in my main file it shows this error. i cant find a solution in the internet for it. i want to render some routes only when there is a user but now it doesnt render anything.

AuthNavigator

import React, { useState, useEffect } from 'react';
import app from './firebase';
import { Router, Routes, Route } from 'react-router-dom';

import AuthStack from './stacks/AuthStack';
import AppStack from './stacks/AppStack';
import StaticStack from './stacks/StaticStack';

function AuthNavigator() {
  const [initializing, setInitializing] = useState(true);
  const [user, setUser] = useState(() => app.auth().currentUser);

  useEffect(() => {
    const unsubscribe = app.auth().onAuthStateChanged((user) => {
      if (user) {
        setUser(user);
      } else {
        setUser(null);
      }
      if (initializing) {
        setInitializing(false);
      }
    });

    // cleanup subscription
    return unsubscribe;
  }, []);

  if (initializing) return 'Loading....';

  return (
    <Router>
      <Routes>
        <Route path="*" element={<StaticStack />} />
        <Route path="auth/*" element={<AuthStack user={user} />} />
        <Route path="app/*" element={<AppStack user={user} />} />
      </Routes>
    </Router>
  );
}
export default AuthNavigator;

App.js

import React from 'react';
import './App.css';
import AuthNavigator from './AuthNavigator';
import { Router } from 'react-router-dom';

function App() {
  return (
    <Router>
      <AuthNavigator />
    </Router>
  );
}

export default App;
Kevin Rump
  • 391
  • 1
  • 3
  • 9

14 Answers14

32

I had the same issue. My issue is because of the following reason. I had a Header component which consists of NavLink which is a router component. I placed this Header component inside the App component. My App component was like this:

function App() {
  return(
      <Header/>
      <Router>
        <Routes>
          <Route path="/" element={<Homepage/>}/>
          <Route path="/shop" element={<Shop/>}/>
          <Route path="/signin" element={<Signin/>}/>
        </Routes>
      </Router>
  )
}

In the above App component, I have placed Header component outside of Router. Since in the Header component I have used NavLink which is a Router component caused this error. Then I moved Header component into the Router component then it worked fine. Finally my code looked like this:

function App() {
  return(
      <Router>
        <Header/>
        <Routes>
          <Route path="/" element={<Homepage/>}/>
          <Route path="/shop" element={<Shop/>}/>
          <Route path="/signin" element={<Signin/>}/>
        </Routes>
      </Router>
  )
}
Vineeth Peddi
  • 486
  • 5
  • 5
26

Already wrapped in Router?

if your component is already wrapped in a Router. Make sure you are importing useLocation from react-router-dom instead of react-router. this worked for me.

tito.300
  • 976
  • 1
  • 9
  • 22
  • I think its good idea to use eslint rule [`no-restricted-imports`](https://eslint.org/docs/latest/rules/no-restricted-imports) to prevent that problem in the future: `name: "react-router"`, `importNames: ["useLocation"]`, `message: "Make sure you are importing useLocation from react-router-dom instead of react-router."` – cimak Sep 16 '22 at 09:31
  • @tito.300 Thank you speed 3 hours because my app use to work and som places I had used react-router. react-router-dom worked!!! – Frederik Nielsen Apr 12 '23 at 13:00
21

Make sure that your App component in index.js is wrapped with BrowserRouter like this

const app = (
  <Provider store={store}>
      <BrowserRouter>
          <App />
      </BrowserRouter>
  </Provider>
);
Mustafa Khalil
  • 342
  • 2
  • 5
7

In case you run into this problem when running a test, don't forget to wrap your import of App in Router as well. My crude example is below.

import { render, screen } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';

import { App } from '../App';

test('renders Box', () => {
  render(
    <BrowserRouter>
      <App />
    </BrowserRouter>
  );
  const boxElement = screen.getByLabelText('box-outline');
  expect(boxElement).toBeInTheDocument();
});
DRobinson
  • 145
  • 1
  • 12
6

I had the same error coming up from inside a test. The component I was testing contained a NavLink component, and I wasn't rendering a Router in the test. This error disappeared after wrapping my component in question with BrowserRouter.

LeahM
  • 61
  • 1
  • 3
3

I had this problem when using {useLocation} from 'react-router-dom'

function App() {
  const { pathname, hash, key } = useLocation();
  //function using pathname hash and key

  return(
    <Router>
      <Header/>
      <Routes>
        <Route path="/" element={<Homepage/>}/>
        <Route path="/shop" element={<Shop/>}/>
        <Route path="/signin" element={<Signin/>}/>
      </Routes>
    </Router>
  )
}

throws the same error even with the in the correct place I fixed it by explicitly wrapping the useLocation() within the router

function App() {
  return(
    <Router>
      <Header/>
      <Inner/>
    </Router>
  )
}
function Inner() {
  const { pathname, hash, key } = useLocation();
  //function using pathname hash and key

  return(
    <Routes>
      <Route path="/" element={<Homepage/>}/>
      <Route path="/shop" element={<Shop/>}/>
      <Route path="/signin" element={<Signin/>}/>
    </Routes>
  )
}
Josh
  • 31
  • 1
2

I had this error because Vite was bundling two copies of the same version of react-router-dom... check the outputted bundle for * React Router DOM and see how many copies there are.

If that's the case, the solution will differ. In my scenario I think it's because I was referencing other local npm packages using file:... once I switched to a npm workspace that fixed it.

David Sherret
  • 101,669
  • 28
  • 188
  • 178
1

So i fixed like this structure

index.js

import { BrowserRouter } from 'react-router-dom'

<Provider store={store}>
    <BrowserRouter>
        <App />
    </BrowserRouter>
</Provider>

App.js

import { Route, Routes, Navigate } from 'react-router-dom'

<Layout>
  <Routes>
    <Route path="/" element={<Navigate to="/home" />} />
    <Route path="/home" element={<Home />} />
    {...}
    <Route path="*" element={<NotFound />} />
  </Routes>
</Layout>

Layout.js

<Fragment>
  <Header></Header>
  <main className="container">{props.children}</main>
</Fragment>

Header.js

import { Link, NavLink } from 'react-router-dom'

<header className={classes.header}>
<nav>
  <NavLink
    className={(navData) => (navData.isActive ? classes.active : '')}
    to="/search"
  >
    Search
  </NavLink>
</nav>
</header>

App.test.js

import { BrowserRouter } from 'react-router-dom';

it('renders learn react link', async () => {
  render(<BrowserRouter><App /></BrowserRouter>)
  const linkElement = await screen.findByText(/home/i)
  expect(linkElement).toBeInTheDocument()
})
lucho20pt
  • 77
  • 5
0

in my case, I faced this error when I used the HOC and context provider and placed my Routing component as the context.provider's child, and export my Provider component by HOC like this:

class Provider extends Component {

render() {
    return (
      <Context.Provider
        value={{
          something: this.state.something
        }}
      >
        <Routing />
      </Context.Provider>
    );
  }
}
export default HOC(Provider)
hossein fti
  • 900
  • 1
  • 6
  • 12
0

im my case, the problem was putting BrowserRouter inside App.js file, solved it by moving this into index.js file and wrapping it around App.js

Former Index.js

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <Provider store={store}>
    <React.StrictMode>
      <PersistGate persistor={persistor} >
        <App/>
      </PersistGate>
    </React.StrictMode>
    </Provider>
  
);
reportWebVitals();

Former App.js

import { BrowserRouter, Routes, Route, useLocation} from "react-router-dom";

const App = () => {
  const {pathname} = useLocation()
  return (
    <div className='app'>
      <BrowserRouter>
          <Routes>
              <Route path='/*' element={<LandingPage />} />           
          </Routes>
       </BrowserRouter> 
    </div>
  );
};
export default App;

New Index.js

import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <Provider store={store}>
    <React.StrictMode>
      <PersistGate persistor={persistor} >
        <BrowserRouter >
            <App/>
        </BrowserRouter>
      </PersistGate>
    </React.StrictMode>
    </Provider>
  
);
reportWebVitals();

New App.js

import { Routes, Route, useLocation} from "react-router-dom";

const App = () => {
  const {pathname} = useLocation()
  return (
    <div className='app'>
        <Routes>
            <Route path='/*' element={<LandingPage />} />           
            <Route path='/registeration'  element={<Registration />} /> 
        </Routes>
    </div>
  );
};
export default App;
PyCobra
  • 7
  • 4
0

If in your App.js you have something like

import { BrowserRouter as Router, Routes, Route }

You need to move BrowserRouter as Router to index.js instead to use useLocation and other hooks

index.js

import { BrowserRouter as Router } from "react-router-dom"
//...
<Router>
  <App />
</Router>
first
  • 616
  • 1
  • 7
  • 13
0

I faced this problem and solved this putting BrowserRouter into App.js file.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { BrowserRouter } from 'react-router-dom'

ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
  <App />
</BrowserRouter>
</React.StrictMode>,
)`
Firoz
  • 21
  • 1
  • 8
0

Possible case description

Another very tricky case, where you can get this error, is if you create your own, separate npm library, where you use useLocation(), useNavigate() or some other members of the react-router (or of the react-router-dom which just reexports many members of the react-router).

Issue

If you export something from your library that is considered to be used inside of a <Router> of some application that uses your library, then those members of your own library most probably won't work. That's because the guard functions, located in source code of useLocation(), useNavigate() hooks (and not only there) will search for their own "library" instance of <Router>, not the one of the application.

Solutions

Solution 1 (simple and tested)

I have used dependency injection. It works for sure. I have checked this. That's how it could look like, if you use a component from your library:

@your-project/library/src/components/NavigationElement.tsx

import { NavigateFunction } from 'react-router-dom';

export interface NavigationElementProps {
  /** This should be `useNavigate` instance, provided by the client application */
  useNavigate: () => NavigateFunction;
}

function NavigationElement(props: NavigationElementProps) {
  const { useNavigate } = props;

  const navigate = useNavigate();

  return (
    <button onClick={() => { navigate('some-path'); }}>
      Navigate to some path
    </button>
  );
}

export default NavigationElement;

@your-project/application/src/App.tsx

import { NavigationElement } from "@your-project/library";
import { BrowserRouter, Route, Routes, useNavigate } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <NavigationElement useNavigate={useNavigate} />
      {/*                ^^^^^^^^^^^^^^^^^^^^^^^^^ - here we inject `useNavigate`
                          of the application itself, the right one */}
      <Routes>
        <Route path="some-path" element={<div>You are at some path</div>} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

Solution 2 (the best, but not tested)

Use peerDependencies clause of the package.json of your library and put react-router-dom (or react-router) there. In this case the code of those dependencies won't be included in the build of your library and the copy of the dependency, used by the application, will be used. This solution seems to be better than the first one from all perspectives, but I didn't test it (that's why I wrote it second). So please write in the comments if it doesn't work for you.

Solution 3 (not recommended, avoid it)

Reexport from your library all members of react-router-dom/react-router, required by the target application, and use in your application them instead. This solution I wouldn't recommend, because the size of your library will be bigger for sure.

Ruslan Zhomir
  • 842
  • 9
  • 27
-4

Try this:

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';