Home  >  Q&A  >  body text

Issues when programmatically redirecting to routes in React Router v6

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;


P粉693126115P粉693126115377 days ago624

reply all(2)I'll reply

  • P粉905144514

    P粉9051445142023-10-31 19:13:17

    How to redirect in React Router v6

    import {  useNavigate  } from "react-router-dom";
    
      const navigate = useNavigate();
      
      const handleClick = () => {
        navigate("/dashboard");
      };

    reply
    0
  • P粉384244473

    P粉3842444732023-10-31 13:19:10

    question

    This is because you are trying to navigate from a navigate property that does not exist, it is undefined.

    this.props.navigate.push("/");
    The

    useNavigate hook is only compatible with function components, so if you want/need to use navigate with a class component, you must convert AddContacts to a function component, or roll your own custom withRouter higher-order component to inject "route props", such as the withRouter HOC v5 from react-router-dom. x did it.

    solution

    I will not introduce how to convert class components into function components. Here is an example of a custom withRouter HOC:

    const withRouter = WrappedComponent => props => {
      const navigate = useNavigate();
      // etc... other react-router-dom v6 hooks
    
      return (
        <WrappedComponent
          {...props}
          navigate={navigate}
          // etc...
        />
      );
    };

    And decorate the AddContacts component with the new HOC.

    export default withRouter(AddContacts);

    The navigate property (and any other properties you set) will now be passed to the decorated component, and this.navigate will now be defined.

    Additionally, the navigation API changed from v5 to v6 and no longer uses direct history objects. navigate is 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 the replace and/or state keys Object/Value.

    Now the navigation is as follows:

    this.props.navigate("/");

    reply
    0
  • Cancelreply