Search code examples
reactjstypescriptreact-router-dom

UseLocation error despite wrapping the component in the router tag


Im new to react routers and currently using the BrowserRouter from react-router-dom with the version react-router-dom": "^6.21.0" Im using the useLocation() to dynmaically set a store variable whenever the path changes.

Here is what im doing:

App.tsx:

function App() {
    const location = useLocation();
    const setMode= useStore((state) => state.setMode);
    useEffect(() => {
        setMode(location.pathname.includes(Constants.AppRoutes.IMAGE_PATH));
    }, [location.pathname, setMode]);

    const routesBody = (
        <div className="main">
            <Comp1/>
            <Comp2/>
            <Comp3/>
        </div>
    );

    const routes = [
        { path: "/", element: <Navigate replace to="bla1" /> },
        {
            path: "/bla1",
            element: routesBody,
        },
        {
            path: "/bla2",
            element: routesBody,
        },
    ];

    return (
        <BrowserRouter>
            <Routes>
                {routes.map((route) => (
                    <Route key={route.path} path={route.path} element={route.element} />
                ))}
            </Routes>
        </BrowserRouter>
    );
}

export default App;

Main.tsx:

ReactDOM.createRoot(document.getElementById('root')!).render(
    <React.StrictMode>
       <App /> 
    </React.StrictMode>,
);

This setup causes the following error

Uncaught Error: useLocation() may be used only in the context of a <Router> component.

What I did:

Moving the <BrowserRouter> tag from the app.tsx to the main.tsx to make the main.tsx look like this:

ReactDOM.createRoot(document.getElementById('root')!).render(
    <React.StrictMode>
        <BrowserRouter>
            <App />
        </BrowserRouter>
    </React.StrictMode>,
);

While this seems to solve the issue and the routing works it causes all my test cases to have the following clause when rendering otherwise all the test cases will fail to render.

render(
            <BrowserRouter>
                <App />
            </BrowserRouter>,
        );

Why cant i just put the <BrowserRouter> in my App.tsx? Am i missing something?


Solution

  • Solved by using the solution found here

    The code looks like this now:

    const AppLayout = () => {
      const location = useLocation();
    
      useEffect(() => {
        //do stuff with the location. 
      }, [location]);
    
      return (
        <div>
                <Comp1/>
                <Comp2/>
                <Comp3/>
        </div>
      );
    };
    
    const router = createBrowserRouter(
      createRoutesFromElements(
        <>
          <Route path="/" element={<Navigate replace to="/bla1"/>} />
          <Route path="/bla1" element={<AppLayout />} />
          <Route path="/bla2" element={<AppLayout />} />
        </>
      )
    );
    
    function App() {
      return <RouterProvider router={router} />;
    }