React-router v6: Cannot read properties of undefined (reading 'pathname') - reactjs

I'm using react-router v6 and I'm trying to use a custom history to be able to navigate in redux actions (outside of a component). So I'm using Router from 'react-router instead of BrowserRouter from 'react-router-dom as mentionned in the doc.
Here is my code:
index.js
import myHistory from './utils/history';
import { Router } from 'react-router';
ReactDOM.render(
<Provider store={store}>
<Router history={myHistory}>
<App />
</Router>
</Provider>,
document.getElementById('root')
);
App.js
import React from 'react';
import MainNavigation from './components/navigations/MainNavigation';
import Routes from './routes/Routes';
const App = () => {
return (
<>
<MainNavigation />
<Routes />
</>
);
};
export default App;
MainNavigation.js
import React from 'react';
import { Link } from 'react-router-dom';
const MainNavigation = () => {
return (
<>
<nav className='navigation'>
<ul>
<li>
<Link to='/'>Home</Link>
</li>
<li>
<Link to='/contact'>Contact</Link>
</li>
<li>
<Link to='/about'>A propos</Link>
</li>
<li>
<Link to='/user-profile'>Votre compte</Link>
</li>
</ul>
</nav>
</>
);
};
export default MainNavigation;
Routes.js
//** Import routers */
import {Route, Routes as Routing } from 'react-router-dom';
const Routes = () => {
return (
<Routing>
<Route path='/' element={<Home />} />
<Route path='/about' element={<About />} />
<Route path='/contact' element={<ContactForm />} />
<Route path='/user-profile' element={<UserAccount />} />
</Routing>
);
};
export default Routes;
I really can't figure out why I got the error message Cannot read properties of undefined (reading 'pathname'). It's working when I swap to BrowserRouter instead of Router but then I can't use history ('navigate' now in v6) in my app.
Thank you.

Your Router needs a location too (e.g. <Router location={myHistory.location} history={myHistory}>).

You need to use unstable_HistoryRouter now
import { createBrowserHistory } from 'history';
import { unstable_HistoryRouter as HistoryRouter } from 'react-router-dom';
let history = createBrowserHistory();
function App() {
return (
<HistoryRouter history={history}>
// The rest of your app
</HistoryRouter>
);
}
history.push("/foo");

Related

basic components not rendering

I'm just starting my first react web app but my components are not rendering. even a simple h1 element directly in the app.js file is not rendering. it did, however, after deleting the Routes, so my best guess is that the problem lies somewhere there.
the code:
app.js
import React, { lazy, Suspense } from 'react'
import './App.css';
import { Routes, Route } from 'react-router-dom'
import { ToastContainer } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css'
const Home = React.lazy(() => import('./pages/Home'))
const App = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<h1>App</h1>
<ToastContainer />
<Routes>
<Route exact path="/" element={Home} />
</Routes>
</Suspense>
)
}
export default App;
Home.js
import React from 'react'
const Home = () => {
return (
<h1>Home Page</h1>
)
}
export default Home
sorry for this very beginner question. please keep in mind that this is my first react web app.
React route accepts ReactElement not ReactNode, no need of exact also
<Routes>
<Route path="/" element={<Home />} />
</Routes>
I think that the tutorial you are using uses the previous react-router API. Please, try this:
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch,
useParams
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}

functional component disappears while using react-router-dom

I just wanted to make a simple project setup with react-router-dom but whenever I'm using route the entire page becomes blank. my Nav disappears. why ?
there was a similar question for class component so it wasn't helpful for me.
App.js :
import "./App.css";
import Nav from "./components/Nav";
import Products from "./components/Products";
import About from "./components/About";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
function App() {
return (
<>
<Router>
<Nav />
<Route path="/about" component={About} />
<Route path="/products" component={Products} />
<About />
</Router>
</>
);
}
export default App;
Nav:
import React from "react";
import Navstyle from "../styles/Nav.module.css";
const Nav = () => {
return (
<nav className={Navstyle.Nav}>
<ul className={Navstyle.nav_links}>
<li>
Home
</li>
<li>
Products
</li>
<li>
About
</li>
</ul>
</nav>
);
};
export default Nav;
other components are just returning h2 tags
You need to use a layout (as a HOC) to add a navbar or other things to your code.
just use the components with routes in your router.
I recommend defining the Layout in another file.
export default function App() {
return (
<Layout>
<Router>
<Route component={Products} path="/products" exact />
<Route component={About} path="/about" exact />
</Router>
</Layout>
);
}
const Products = () => {
return <p>Products</p>;
};
const About = () => {
return <p>about</p>;
};
const Navbar = () => {
return <p>navbar</p>;
};
const Layout = ({ children }) => {
return (
<div>
<Navbar />
<div>{children}</div>
</div>
);
};
I find out ! the problem was YouTube videos I guess. first of all you must add BrowserRouter to your index.js not app.js , like this :
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
reportWebVitals();
after that you must use react router in that way , not the way I tried first :
import "./App.css";
import Nav from "./components/Nav";
import Products from "./components/Products";
import About from "./components/About";
import { Route, Routes } from "react-router-dom";
function App() {
return (
<>
<Nav />
<Routes>
<Route path="/About" element={<About />} />
</Routes>
</>
);
}
export default App;
during the changes of react-router-dom in version 6 , this is the new way of using router.
the link of docs :
https://reactrouter.com/docs/en/v6/getting-started/overview

Link of 'react-router-dom' not acting as links

I have a Link in my Footer.js, and for some reason, it's not working as links in the browser. Like not showing up a pointer on the link etc. I have multiple Links in my Nav component. They all are working fine, but if I place a Link in any other component, it doesn't work. I have tried using BrowserRouter instead of HashRouter and NavLink instead of Link, but the problem still exists. It seems like a reckless mistake, though.
For now, I have this as a static website. That's why I haven't wrapped my components in Switch and Route.
Footer.js
import { Link } from 'react-router-dom'
const Footer = () => {
return (
<div>
<h1>Create group!</h1>
<Link to="/" className="rounded">Get Started</Link>
</div>
)
}
export default Footer
App.js:
import Footer from './Footer'
import { HashRouter } from 'react-router-dom'
const App = () => {
return (
<HashRouter basename="/">
<Nav />
<Home />
<About />
<HowItWorks />
<GroupCarousel />
<EventCarousel />
<Footer />
</HashRouter>
);
}
export default App;
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Any help would be appreciated.
You have to define your routes inside HashRouter using Switch and Route tags which is to be used inside the app. Otherwise your routes won't work. Try following code and it will work as expected.
Footer.js
import { Link } from 'react-router-dom'
const Footer = () => {
return (
<div>
<h1>Create group!</h1>
<Link to="/" className="rounded">Get Started</Link>
</div>
)
}
export default Footer
App.js
import Footer from './Footer'
import { HashRouter } from 'react-router-dom'
const App = () => {
return (
<HashRouter basename="/">
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</HashRouter>
);
}
export default App;
Home.js
import React from 'react'
...
const Home = () => {
return (
<>
<Nav />
<Home />
<About />
<HowItWorks />
<GroupCarousel />
<EventCarousel />
<Footer />
</>
):
}
export default Home;

history push with switch doesn't redirect

I'm new to react.
I've used CRA to create my app.
I try to build a smooth full page transition, not only on the component who's rendered as we can do with react-transition-group
To do so, I try to manually redirect when I click on a tag.
But only the url is changed but the page is not re-rendered...
I've tried with this.context (undefined), < Redirect >, I red the docs and many articles but couldn't figure out how it can work.
Here is my code
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
serviceWorker.register();
App.js
import React, { Component } from 'react'
import { BrowserRouter as Router, Switch, Route, withRouter } from 'react-router-dom';
import './App.scss';
import history from 'js/core/history.js'
class App extends Component {
constructor(props) {
super(props);
this.state = {
isRedirecting: false
}
this.isRedirecting = false;
this.taContainer = React.createRef();
}
redirectHandler(location) {
if(location != null && location != undefined && !this.state.isRedirecting) {
this.setState({isRedirecting: true})
setTimeout(() => {
history.push(location);
this.setState({isRedirecting: false})
}, 1000)
}
}
render() {
return (
<div className="app">
<div className="inner-app">
<BackScene></BackScene>
<Router>
<Switch>
<Route exact path='/' render={(props) => <Home {...props} onClick={this.redirectHandler.bind(this)} />} />
<Route exact path={'/experiments'} render={(props) => <Experiments {...props} onClick={this.redirectHandler.bind(this)}/>
<Route exact path={'/experiments/:cat'} render={(props) => <Experiments {...props} />} />
<Route exact path={'/experiments/:cat/:slug'} render={(props) => <SingleProject {...props} />} />
<Route exact path={'/shader'} render={(props) => <ShaderTemplatePage {...props} />} />
</Switch>
</Router>
<div className="ta" ref={this.taContainer}>
<div className="ta-first"></div>
<div className="ta-second"></div>
</div>
</div>
</div>
);
}
}
export default withRouter(App);
Home.js
import React, { Component } from 'react'
export default class Home extends Component {
render() {
return (
<div className='home page'>
<div className="inner-home">
<div className="content">
<h1 className='title'>Title</h1>
<a className='button' onClick={() => {this.props.onClick('/experiments')}}>Get started !<span></span></a>
<ul className="socials">
<li><i className='icon icon-twitter'></i></li>
<li><i className='icon icon-instagram'></i></li>
</ul>
</div>
</div>
</div>
)
}
}
history.js
import { createBrowserHistory } from "history";
export default createBrowserHistory();
Can you try passing history object as props to the <BrowserRouter> component in the index.jsx file?
import history from 'js/core/history.js'
<BrowserRouter history={history}>
<App />
</BrowserRouter>

cannot read property history because it's undefined but it is

I am getting the error cannot read property history but I defined it.
This used the work when I had it in main.jsx in my client folder but now it stops working.
The app file is in my imports folder.
import { Router, Route, Switch, Redirect } from "react-router-dom";
import createBrowserHistory from "history/createBrowserHistory";
const history = createBrowserHistory();
// App component - represents the whole app
export class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="container">
<Router history={history}>
<Switch>
<Route path="/" exact component={Home} />
<Route
path="/dashboard"
render={() =>
this.props.currentUser ? <Dashboard /> : <NoPermission />}
/>
<Route path="/test" component={Test} />
<Route component={NotFound} />
</Switch>
</Router>
</div>
);
}
}
more info:
import createBrowserHistory from "history/createBrowserHistory";
within that file createBrowserHistory is the default export.
export.default = createBrowserHistory;
When trying BrowserRouter instead of router and deleting the history const and props I get following error in my console.
modules.js:26944 Uncaught TypeError: Cannot read property 'history' of undefined
at Link.render (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:26944)
at modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:18399
at measureLifeCyclePerf (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:17679)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:18398)
at ReactCompositeComponentWrapper._renderValidatedComponent (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:18425)
at ReactCompositeComponentWrapper.performInitialMount (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:17965)
at ReactCompositeComponentWrapper.mountComponent (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:17861)
at Object.mountComponent (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:10622)
at ReactDOMComponent.mountChildren (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:16977)
at ReactDOMComponent._createInitialChildren (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:14176)
When using BrowserRouter in my main.jsx I can get it working. I can change URL's but the new views do not render. So I think there still is something wrong with the history. In this case I have not defined it but I am not receiving any errors. Any way how I can check or fix this?
import React from "react";
import { Meteor } from "meteor/meteor";
import { render } from "react-dom";
import "../imports/startup/accounts-config.js";
import App from "../imports/layouts/App.jsx";
import Test from "../imports/Test.jsx";
import { BrowserRouter } from "react-router-dom";
Meteor.startup(() => {
render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("render-target")
);
});
Going further on Kyle's answer I added withrouter to my test component.
import React, { Component } from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router";
class Test extends Component {
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
render() {
const { match, location, history } = this.props;
return (
<div>
<p>This is a test</p>
<p>
You are now at {location.pathname}
</p>
</div>
);
}
}
export default withRouter(Test);
I am using NavLinks to link to this route in my navigation bar component.
<NavLink to="/test" activeClassName="active">
Test
</NavLink>
However clicking those links does not render the test page. (the address in the URL bar does change). When I press refresh in the browser the page loads and the location.pathname shows the proper location.
If I remove the withrouter the functionality is the same.
I got it working by not using a component to nest the router in.
If somebody can explain me why I would greatly appreciate it.
import Navbar from "../components/Navbar.jsx";
import AccountsUIWrapper from "../components/AccountsUIWrapper.jsx";
//import pages
import Home from "../pages/Home.jsx";
import Dashboard from "../pages/Dashboard.jsx";
import Test from "../Test.jsx";
import NotFound from "../pages/NotFound.jsx";
import NoPermission from "../pages/NoPermission.jsx";
let currentUser = Meteor.user();
const App = () =>
<Router>
<div>
<Navbar currentUser={currentUser} />
<AccountsUIWrapper />
<p>
{currentUser ? currentUser._id : "current user id not found"}
</p>
<Switch>
<Route exact path="/" component={Home} />
<Route
path="/dashboard"
render={() => (currentUser ? <Dashboard /> : <NoPermission />)}
/>
<Route path="/test" component={Test} />
<Route component={NotFound} />
</Switch>
</div>
</Router>;
export default App;
React Router 4 has history baked into it. You can see from the documentation for BrowserRouter, HashRouter, and MemoryRouter that there is no argument for history.
If you would like to access history in React Router v4 you should use the withRouter HoC on the component that you wish to have access to it in. withRouter will make ({match, history, location }) available inside any component that it wraps.
As you can see from this line of code: var _createBrowserHistory = require('history/createBrowserHistory'); which is line 13 in BrowserRouter.js and HashRouter.js history is already included for you. It is also included in the memory router on line 9 of MemoryRouter.js.
Try changing your import at the top to import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom"; and then remove history={ history } from <Router />.
EDIT: Please take a look at the documentation for React Router 4. Here is a basic example.
Here is a post of the code incase the link ever goes dead.
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
)
const Home = () => (
<div>
<h2>Home</h2>
</div>
)
const About = () => (
<div>
<h2>About</h2>
</div>
)
const Topics = ({ match }) => (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/rendering`}>
Rendering with React
</Link>
</li>
<li>
<Link to={`${match.url}/components`}>
Components
</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
<Route path={`${match.url}/:topicId`} component={Topic}/>
<Route exact path={match.url} render={() => (
<h3>Please select a topic.</h3>
)}/>
</div>
)
const Topic = ({ match }) => (
<div>
<h3>{match.params.topicId}</h3>
</div>
)
export default BasicExample

Resources