Sorry if this is a dumb question but I'm trying to get my react chops up and build a simple site with a select dropdown which should route to a URL when selected. However I'm getting this error. Or if there's a better way to do this with hooks, I am all ears :). Thanks
×
TypeError: Cannot read properties of undefined (reading 'push')
DropDown.onChange
src/components/Dropdown.js:10
7 |
8 | class DropDown extends Component {
9 | onChange = (e) => {
> 10 | this.props.history.push(`/${e.target.value}`);
11 | }
12 |
13 | render() {
Below is my code
import React, { Component } from 'react'
import '../App.css'
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, withRouter } from "react-router-dom";
class DropDown extends Component {
onChange = (e) => {
this.props.history.push(`/${e.target.value}`);
}
render() {
return (
<div>
<label htmlFor="pests">Choose a pest:</label>
<select onChange={this.onChange}>
<option value="ants">Ants</option>
<option value="wasps">Wasps</option>
</select>
</div>
)
}
}
export default DropDown;
Here's my router code
function App() {
return (
<div className="main">
{/* <Navbar/> */}
<Header />
<NavbarBasic />
<Dropdown />
{/* These are the main routes and subpages */}
<Routes>
<Route path='/' element={<Home />} />
<Route path='/about' element={<About />} />
<Route path='/pests-we-treat' element={<Pests />} />
<Route path='/services' element={<Services />} />
<Route path='/contact' element={<Contact />} />
<Route path='/ants' element={<Ants />} />
<Route path='/wasps' element={<Wasps />} />
</Routes>
</div>
);
}
export default App;
CodePudding user response:
Class component to functional component
Transform your class component in a functional componente and import useHistory like this :
import { useHistory } from "react-router-dom";
...
let history = useHistory();
history.push(`/${e.target.value}`);
Another way, using JS
import React, { Component } from 'react';
// import { BrowserRouter, Route, withRouter } from "react-router-dom";
class DropDown extends Component {
onChange = (e) => {
// this.props.history.push(`/${e.target.value}`);
window.location.href = `/${e.target.value}`;
}
render() {
return (
<div>
<label htmlFor="pests">Choose a pest:</label>
<select onChange={this.onChange}>
<option value="ants">Ants</option>
<option value="wasps">Wasps</option>
</select>
</div>
);
}
}
export default DropDown;
Another method mixing class component and React Hooks
dropdownRouter.tsx
import { createBrowserHistory } from 'history';
export default function DropdownPush(path: string) {
let history = createBrowserHistory();
history.push(`/${path}`);
}
OR
import { useHistory } from 'react-router-dom';
export default function DropdownPush(path: string) {
const history = useHistory();
history.push(`/${path}`);
}
OR if you are using v6 react-router-dom useHistory() was replaced by useNavigate()
import { useNavigate } from "react-router-dom";
export default function DropdownPush(path: string) {
const navigate = useNavigate();
navigate(`/${path}`);
}
dropdown.tsx
import React, { Component } from 'react';
import DropdownPush from './dropdownRouter';
class DropDown extends Component {
constructor(props) {
super(props);
}
onChange = (e) => {
// this.props.history.push(`/${e.target.value}`);
// JS redirect method
// window.location.href = `/${e.target.value}`;
// Using Hook
DropdownPush(e.target.value);
};
render() {
return (
<div>
<label htmlFor="pests">Choose a pest: </label>
<select onChange={this.onChange}>
<option value="ants">Ants</option>
<option value="wasps">Wasps</option>
</select>
</div>
);
}
}
export default DropDown;
CodePudding user response:
I expect you want to wrap your Dropdown
component in the withRouter
higher-order component. That would usually happen in the export:
import { withRouter } from "react-router";
class DropDown extends Component {
// ...
}
export default withRouter(Dropdown);
The alternative way to access history
is to use the useHistory
hook, and the docs contain a good example of how to use it.