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
Issue
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>
Solution
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>
react-router-dom#6.4 Data APIs
If 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} />
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')
);
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
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>
);
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>
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>
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>
);
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>
);
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>
);
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
Your links just needs to be within a BrowserRouter component since you use v6
After importing
<BrowserRouter>
<Link to='page'>
</BrowserRouter>
Related
We are working on project of clone of flipkart.com.We are working on team.so we have distributed our works. One of guy worked on landing page with material UI and i am working on product page with chakra ui but after merging app is not working and producing unfamiliar error.
So, provide some solution so we can make our presentation.
in index.js i have written this code
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import FlipkartStore from './Components/Redux_Implementation/Store/Store';
import { BrowserRouter } from 'react-router-dom';
import { ThemeProvider } from '#material-ui/core/styles';
import { createTheme } from '#material-ui/core/styles';
import { ChakraProvider, extendTheme } from '#chakra-ui/react';
const muiTheme = createTheme();
const theme = extendTheme();
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={FlipkartStore}>
<ChakraProvider theme={theme} >
<ThemeProvider theme={muiTheme}>
<BrowserRouter>
<App />
</BrowserRouter>
</ThemeProvider>
</ChakraProvider>
</Provider>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
reportWebVitals();
its showing this error
if am removing chakra provider page is working but my product page css is not working
You can wrap the ChakraProvider only for your page as needed.
If you are using React Router. You could wrap the provider only for your path.
Example:
<Switch>
<Route path="/products">
<ChakraProvider> /* 👈 wrap only for your products page */
<Products />
</ChakraProvider>
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
wrap your route inside ChakraProvider.
<Switch>
<Route path='/your_path'>
<ChakraProvider>
<YourComponent />
</ChakraProvider>
</Route>
<Route path ='/your_path_2' element={<YourOtherComponent />} />
</Switch>
Just wrap your route inside the route.
The component you want to use you can wrap it in chakra provider.
<Route path='/'>
<ChakraProvider>
<Component you want />
</ChakraProvider>
</Route>
Worked for me:
<ThemeProvider theme={muiTheme}>
<ChakraProvider theme={chakraTheme}>
...
</ChakraProvider>
</ThemeProvider>
I'm learning react routing but when I try to use BrowserRouter I'm getting the following error:
Matched leaf route at location "/project" does not have an element.
This means it will render an <Outlet /> with a null value by default
resulting in an "empty" page.
in Routes (created by Profile)
in Profile (created by App)
in App
PFA the code below.
index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<App />
</StrictMode>
);
APP.JS
import "./styles.css";
import Profile from "./Profile";
import { BrowserRouter } from "react-router-dom";
export default function App() {
return (
<div className="App">
<BrowserRouter>
<Profile />
</BrowserRouter>
</div>
);
}
PROFILE.JS
import Home from "./Home";
import Projects from "./Projects";
import Blogs from "./Blogs";
import { Route, Routes, Switch } from "react-router-dom";
import { BrowserRouter, Link } from "react-router-dom";
const Profile = () => (
<div>
<Routes>
<Route exact path="/" component={Home} />
<Route path="/project" component={Projects} />
<Route path="/blog" component={Blogs} />
</Routes>
</div>
);
export default Profile;
HOME.JS
const Home = () => {
return <div>Hi im Home page</div>;
};
export default Home;
Please note project.js and blog.js is similar to home.js
You appear to be using react-router-dom#6. The Route component API changed significantly from v5. A single element prop replaced the component and render and children function props that takes a ReactNode, a.k.a. JSX, value.
Replace the component prop with the element prop and render the routed components as JSX.
const Profile = () => (
<div>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/project" element={<Projects />} />
<Route path="/blog" element={<Blogs />} />
</Routes>
</div>
);
See the Upgrading from v5 migration guide for other breaking changes between v5 and v6.
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
Issue
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>
Solution
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>
react-router-dom#6.4 Data APIs
If 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} />
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')
);
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
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>
);
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>
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>
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>
);
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>
);
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>
);
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
Your links just needs to be within a BrowserRouter component since you use v6
After importing
<BrowserRouter>
<Link to='page'>
</BrowserRouter>
After updating React Router V2.x on V4.x, all routes go to the main page.
Here is the route on V2.x:
import {Router, Route, hashHistory } from 'react-router'
const routes = <Route component={App}>
<Route path="/results" component={Results} />
<Route path="/" component={Voting} />
</Route>;
ReactDOM.render(
<Router history={hashHistory}>{routes}</Router>,
document.getElementById('app')
);
And these are routes on V4.x:
index.jsx file:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import App from './components/App';
import Voting from './components/Voting';
import Results from './components/Results';
const withAppLayout = Component => props => <App><Component {...props} /></App>
const routes = <Switch>
<Route exact path="/" component={withAppLayout(Voting)} />
<Route path="/results" component={withAppLayout(Results)} />
</Switch>;
ReactDOM.render(
<Router component={App}>
{routes}
</Router>,
document.getElementById('app')
);
App.jsx File:
import React from 'react';
import {List} from 'immutable';
const pair = List.of('Trainspotting', '28 Days Later');
export default React.createClass({
render: function () {
console.log(this.props.children);
return React.cloneElement(this.props.children, {pair: pair});
}
});
Voting.jsx File:
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Winner from './Winner';
import Vote from './Vote';
export default React.createClass({
mixins: [PureRenderMixin],
render: function () {
return <div>
{this.props.winner ?
<Winner ref="winner" winner={this.props.winner} /> :
<Vote {...this.props} />
}
</div>;
}
});
Results.jsx File:
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
export default React.createClass({
mixins: [PureRenderMixin],
render: function () {
return <div>Hello from results!</div>
}
});
How to fix this error?
One thing would be to use :
<Route exact path="/" component={withAppLayout(Voting)} />
The exact will make sure that only that exact path is going to match. But if you have the path="/" after the others, the others should match first though. Is this the real code you're using ?
Edit: See a complete version below.
import {BrowserRouter, Route, Switch} from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route exact path="/" component={Voting} />
<Route path="/results" component={Results} />
</Switch>
</BrowserRouter>,
document.getElementById('app')
);
Then, if that works out, you can move the Switch part into an App Component. Also, if you want to use hash history, you need to use a HashRouter that basically initializes a Router with a hash history.
In my index.js file:
import React from 'react';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom';
import App from './App';
import Contact from './Contact';
import ReactDOM from 'react-dom';
//import RouterMapping from './RouterMapping';
const RouterMapping = () => (
<Router>
<Route exact path='/' component={App} />
<Route path='/contact' component={Contact} />
</Router>
);
ReactDOM.render(
<RouterMapping />,
document.getElementById('root')
);
When rendering the page /, it displays nothing (should go to App component per my understanding. The App component itself is running OK if I replace:
ReactDOM.render(
<RouterMapping />,
document.getElementById('root')
);
to
ReactDOM.render(
<App />,
document.getElementById('root')
);
Did I do something fundamentally wrong? Newbie to React...
Update on Mar 16
I think I figured out how to make the router work.
I have refactored my RouterMapping to RoutingConfig as below:
import React from 'react';
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom';
import Home from './Home';
import Contact from './Contact';
const RoutingConfig = () => (
<Router>
<div>
<Route exact path="/" component={Home}/>
<Route path="/contact" component={Contact}/>
</div>
</Router>
);
export default RoutingConfig;
Nothing peculiar.
Now, instead of rendering RoutingConfig in my index.js, I still render the App component in my index.js:
ReactDOM.render(
<App />,
document.getElementById('root')
);
The routing mapping is done now in App.js:
class App extends Component {
render() {
return (
<RoutingConfig />
);
}
}
Now it works. Please see attached screenshot:
My explanation
I think the key here is to demote the RoutingConfig to App.js. From index.js render App.js, App.js will act as the entry point to my whole app and determine which component (Home, Contact) to load based on routing.
Above for your information and hope it is helpful.