Reputation: 1007
I have a navbar that is rendered in every route while the route changes on click.
./components/navbar.jsx
import React, { Component } from 'react';
import '../App.css';
import { Link } from 'react-router-dom';
class Navbar extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div id = 'navbar'>
<div className='name-head'>
My Name
</div>
<div id = 'nav-links-container'>
<Link to='/experiences'>
<div className = 'nav-links'>
Experiences
</div>
</Link>
<div className = 'nav-links'>
Projects
</div>
<div className = 'nav-links'>
Skills
</div>
<div className = 'nav-links'>
Resume
</div>
</div>
</div>
);
}
}
export default Navbar;
./components/experiences.jsx
import React, { Component } from 'react';
class Experiences extends Component {
render() {
return (
<div>
<h1>hi</h1>
</div>
);
}
}
export default Experiences;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import reportWebVitals from './reportWebVitals';
import Navbar from './components/Navbar';
import Home from './components/Home';
import Experiences from './components/experience';
import {
BrowserRouter as Router,
Routes,
Route
} from 'react-router-dom';
ReactDOM.render(
<React.StrictMode>
<Navbar />
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/experiences" element={<Experiences />} />
</Routes>
</Router>
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
The error doesn't come when I remove the <Link>
from the experiences tag in navbar.
There is a similar question posted here: Error: useHref() may be used only in the context of a <Router> component
but doesn't help.
I'm using react router v6
Upvotes: 98
Views: 134329
Reputation: 15413
@Yilmaz gives an excellent answer about this also occurring in a testing environment and I can confirm that is the case having experienced before and would like to offer a condensed answer of all the good ones given here.
Yes Link
component will try to reach up and find the context object at the top of the component hierarchy and yes indeed this occurs in a testing environment as well.
Whenever we render one of these different react router component so something like Link
or some other, even though we are in a test environment and we don’t really care about navigation at all, we still have to provide one of these three options available to us, we can try to wrap our component that we are trying to test in a:
How do you know which one to use? What is the difference?
Well, a BrowserRouter
stores current URL in the address bar, a HashRouter
stores current URL in the # part of the address bar and a MemoryRouter
stores current URL in memory.
Like @Yilmaz I would also recommend going with a MemoryRouter
in a testing environment, although there are some tests where BrowserRouter
might be best to use long term.
Upvotes: 0
Reputation: 49182
This error happens because Link
component needs to reach out to react-router
context object. Your Navbar component is using Link
component but Navbar
is not wrapped by router context.
A similar error happens in a testing environment. If you have a component that uses Link
component and if you render this component in a testing environment, you will get the same error because Link
component needs to access a router context. In the case of test environment:
import { render } from "@testing-library/react";
// this will throw same error
test("testing", () => {
render(<ComponentRendersLink/>);
});
Solution in this case to wrap it with a router
// there are more router options
import { MemoryRouter } from "react-router-dom";
render(
<MemoryRouter>
<ComponentRendersLink />
</MemoryRouter>
);
Upvotes: 2
Reputation: 202618
You are rendering the navbar outside the routing context. The Router
isn't aware of what routes the links are attempting to link to that it is managing. The reason routing works when directly navigating to "/experiences"
is because the Router
is aware of the URL when the app mounts.
<Navbar /> // <-- outside router!!
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/experiences" element={<Experiences />} />
</Routes>
</Router>
Move it inside the routing context so the Router
is aware and can manage routing correctly.
<Router>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/experiences" element={<Experiences />} />
</Routes>
</Router>
[email protected]
Data APIsIf you are using the new Data routers you can hit this issue if you attempt to render a header/navbar outside the RouterProvider
component. For this you can create a layout route that is part of the routing configuration passed to createBrowserRouter
(and other variants).
Example:
const AppLayout = () => (
<>
<Navbar />
<Outlet />
</>
);
const router = createBrowserRouter(
createRoutesFromElements(
<Route element={<AppLayout />}>
<Route path="/" element={<Home />} />
<Route path="/experiences" element={<Experiences />} />
</Route>
)
);
...
<RouterProvider router={router} />
Upvotes: 169
Reputation: 20078
In react-router-dom:6.x and react:18.x, we should use the Router in the following way to resolve the issue:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { App } from './App.js';
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Router> // Router
<App /> // Application
</Router>
</React.StrictMode>
);
Upvotes: 10
Reputation: 181
If you are still having problem with this one, it is because react-router-dom
relies on React context to work when you try to unit-test it. This makes <Link />
or <Route />
obsolete.
Try reading the react-router-dom
documentation.
Instead of using
render(<Example />)
that have either or inside it, you can try
render(<MemoryRouter>
<Example />
</MemoryRouter>)
Hope this solves your problem
Upvotes: 18
Reputation: 79
Your links just needs to be within a BrowserRouter component since you use v6 After importing
<BrowserRouter>
<Link to='page'>
</BrowserRouter>
Upvotes: 1
Reputation: 622
This is very much an edge case, but in my case it turned out a lib I develop had react-router-dom: 6.0.2
installed and project that uses it v6.3.0
Upvotes: 0
Reputation: 53
Install in your project React Router v6.
npm install react-router-dom@6
Then use BrowserRouter
in your index.js
file, below like this:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
Upvotes: 5
Reputation: 737
React Router v6 this problem common one, you can simply replace "index.js" code. you will got solution-
import React from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
Upvotes: 2
Reputation: 135
Wrap navbar with BrowserRouter
import { BrowserRouter, Routes, Route } from "react-router-dom";
<BrowserRouter>
<AppNavBar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/wall" element={<WallPost />} />
</Routes>
</BrowserRouter>
Upvotes: 5
Reputation: 81
Links are inside Navbar & Navbar is outside of Router => links are outside of Router => Router will not manage Links
Solution
Move the Navbar into Router section. Example:
<Router>
<Navbar /> // <===========
<Routes>
<Route />
<Route />
</Routes>
</Router>
Upvotes: 8
Reputation: 2247
in React Route v6 you can solve this giving the route context to your entire App with <BrowserRouter>
This is an complete example of index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { App } from './components/App/App.jsx';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter> //that is the key
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
Upvotes: 36