I want to perform navigation on some user actions, such as onSubmit of a button. Assuming the user clicks the "Add Contact" button, I want react-router to redirect in the homepage "/". Currently I'm facing this issue --> TypeError: Cannot readproperties of undefined (reading 'push'). As a beginner, I would really appreciate the help from experts.
AddContacts.js
import React, { Component } from "react";
import { Consumer } from "../../context";
import TextInputGroup from "../layout/TextInputGroup";
import { v4 as uuidv4 } from "uuid";
import { useNavigate } from "react-router-dom";
class AddContacts extends Component {
state = {
name: "",
email: "",
phone: "",
errors: {},
};
onSubmit = (dispatch, e) => {
e.preventDefault();
const { name, email, phone } = this.state;
//Check for errors
if (name === "") {
this.setState({ errors: { name: "Name is required" } });
return;
}
if (email === "") {
this.setState({ errors: { email: "Email is required" } });
return;
}
if (phone === "") {
this.setState({ errors: { phone: "Phone is required" } });
return;
}
const newContact = {
id: uuidv4(),
name,
email,
phone,
};
dispatch({ type: "ADD_CONTACT", payload: newContact });
this.setState({
name: "",
email: "",
phone: "",
errors: {},
});
this.props.navigate.push("/");
};
onChange = (e) => this.setState({ [e.target.name]: e.target.value });
render() {
const { name, email, phone, errors } = this.state;
return (
<Consumer>
{(value) => {
const { dispatch } = value;
return (
<div className="card mb-3">
<div className="card-header">Add Contacts</div>
<div className="card-body">
<form onSubmit={this.onSubmit.bind(this, dispatch)}>
<TextInputGroup
label="Name"
name="name"
placeholder="Enter Name..."
value={name}
onChange={this.onChange}
error={errors.name}
/>
<TextInputGroup
label="Email"
name="email"
type="email"
placeholder="Enter Email..."
value={email}
onChange={this.onChange}
error={errors.email}
/>
<TextInputGroup
label="Phone"
name="phone"
placeholder="Enter Phone..."
value={phone}
onChange={this.onChange}
error={errors.phone}
/>
<input
type="submit"
value="Add Contact"
className="btn btn-light btn-block mt-3"
/>
</form>
</div>
</div>
);
}}
</Consumer>
);
}
}
export default AddContacts;
This is the App.js file
import React, { Component } from "react";
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
import Contacts from "./components/contacts/Contacts";
import Header from "./components/layout/Header";
import AddContacts from "./components/contacts/AddContacts";
import About from "./components/pages/About";
import { Provider } from "./context";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
function App() {
return (
<Provider>
<BrowserRouter>
<div className="App">
<Header branding="Contact manager" />
<div className="container">
<Routes>
<Route path="/" element={<Contacts />} />{" "}
<Route path="/contact/add/*" element={<AddContacts />} />{" "}
<Route path="about/*" element={<About />} />{" "}
</Routes>{" "}
</div>{" "}
</div>{" "}
</BrowserRouter>{" "}
</Provider>
);
}
export default App;
How to redirect in React Router v6
import { useNavigate } from "react-router-dom"; const navigate = useNavigate(); const handleClick = () => { navigate("/dashboard"); };question
This is because you are trying to navigate from a
navigateproperty that does not exist, it is undefined.this.props.navigate.push("/");TheuseNavigatehook is only compatible with function components, so if you want/need to usenavigatewith a class component, you must convertAddContacts code> to a function component, or roll your own customwithRouterhigher-order component to inject "route props", such as thewithRouterreact-router-dom. x did it.HOCv5 fromsolution
I will not introduce how to convert class components into function components. Here is an example of a custom
withRouterHOC:const withRouter = WrappedComponent => props => { const navigate = useNavigate(); // etc... other react-router-dom v6 hooks return ( <WrappedComponent {...props} navigate={navigate} // etc... /> ); };And decorate the
AddContactscomponent with the new HOC.The
navigateproperty (and any other properties you set) will now be passed to the decorated component, andthis.navigatewill now be defined.Additionally, the navigation API changed from v5 to v6 and no longer uses direct
historyobjects.navigateis a function not an object. To use you call the function and pass 1 or 2 arguments, the first is the target path and the second is an optional "option" with thereplaceand/orstatekeys Object/Value.Now the navigation is as follows:
this.props.navigate("/");