0

I wan to navigate to the dashboard page immediately after I submit the details. Here this is my CreateMonthWallet class where I am creating different for different months. Inside this create form all the information are there which are needed to be collected by the user. Once the user click the create button, the user should navigate back to the Dashboard page. Below given is the code of CreateMonthWallet class. When I run the code, once after clicking the cleate button it gives me the message of error but the data is updated to database but still its showing the message of error on the localhost page and doesn't navigating to the dashboard.

import axios from 'axios'
import React, { Component } from 'react'

class CreateMonthWallet extends Component {

    constructor(props) {
        super(props)

        this.state = {
            name: '',
            accountNumber: '',
            description: '',
            priority: ''
        }
    }

    changeHandler = (event, fieldName) => {
        this.setState({
            [fieldName]: event.target.value
        })
    }

    submitHandler = (event) => {
        const newWallet = {
            name: this.state.name,
            accountNumber: this.state.accountNumber,
            description: this.state.description,
            priority: this.state.priority
        }
        axios.post('http://localhost:8080/monthwallet', newWallet)
            .then((res) => {
                this.props.history.push('/Dashboard')
            }).catch((err) => {
                alert("Error")
            })
        event.preventDefault()
    }

    render() {
        return (
            <div className="project">
                <div className="container">
                    <div className="row">
                        <div className="col-md-8 m-auto">
                            <h5 className="display-4 text-center">Create Wallet</h5>
                            <hr />
                            <form onSubmit={(event)=>this.submitHandler(event)}>
                                <div className="form-group">
                                    <input type="text" onChange={(event) => this.changeHandler(event, "name")} className="form-control form-control-lg " placeholder="Account Name" />
                                </div>
                                <div className="form-group">
                                    <input type="text" onChange={(event) => this.changeHandler(event, "accountNumber")} className="form-control form-control-lg" placeholder="Account No" />
                                </div>
                                <div className="form-group">
                                    <textarea onChange={(event) => this.changeHandler(event, "description")} className="form-control form-control-lg" placeholder="Description"></textarea>
                                </div>
                                <div className="form-group">
                                    <select className="form-control form-control-lg" onChange={(event) => this.changeHandler(event, "priority")}>
                                        <option value={3}>Display Priority</option>
                                        <option value={1}>High</option>
                                        <option value={2}>Medium</option>
                                        <option value={3}>Low</option>
                                    </select>
                                </div>
                                <input type="submit" className="btn btn-dark btn-block mt-4" value="Create" />
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

export default CreateMonthWallet

Edit: Adding the content of function App to the question. As it became relevant.

function App() {
    return (
        <Router>
            <div>
                <Nav />
                <Routes>
                    <Route path="/" element={<Welcome />} exact />
                    <Route path="/Dashboard" element={<Dashboard />} exact />
                    <Route path="/CreateMonthWallet" element={<CreateMonthWallet />} exact />
                    <Route path="*" element={<NotFound />} exact />
                </Routes>
            </div>
        </Router>
    )
}
Sarwvidya
  • 13
  • 4
  • Looks good to me. What error do you get if you catch err and pass it to alert("Error"). Do you have this component nested inside ? event.preventDefault usually comes first, but I don't think this changes anything here – Felipe de Abreu Prazeres Dec 26 '22 at 12:21
  • In both the cases, I get the alert of error i.e. with then as well with catch. But if I replace "this.props.history.push('/Dashboard')" with "alert("Success")", Then I receive the alert of success if all the validations are fulfilled. Right now even tough while passing the valid data it gives an alert of error but when I check my database the following entry has updated. The only issue I'm facing is that I'm unable to navigate back to my dashboard page immediately after passing all the valid data and clicking the create button page, rest everything is working fine. – Sarwvidya Dec 27 '22 at 16:25
  • OK. Good. So your problem resides in this.props.history.push("/dashboard"). Can you console.log(this.props.history) to make sure you are receiving it from . Lets make sure console.log is not returning undefined. Could you post the parent component that calls . As a sidenote, I could provide you a funcional component (which is a lot easier to write and read) so that we can use hooks to have access to history. If that is an option, let me know so I translate this to a funcional component. – Felipe de Abreu Prazeres Dec 27 '22 at 20:00
  • This is my function in App.js file function App() { return (
    } exact /> } exact /> } exact /> } exact />
    ); }
    – Sarwvidya Dec 28 '22 at 07:08

2 Answers2

0

Looks like you did not create a history variable yet. It's a piece of cake.

This variable that you are going to create, named history, will be responsible for storing the history of your browsing within your app.

With history you earn the ability to goBack(), for example. Notice that react-router is now favoring navigate instead. You can have a look later at the link below later for upgrading to newer versions.

react-router go back a page how do you configure history?

But let's keep ourselves in the problem here.

 import {BrowserRouter, } from "react-router-dom";
 import { createBrowserHistory } from 'history';


 function App() {
     const history = createBrowserHistory() //creates the variable history
     return (
        <BrowserRouter>
            <div>
                <Nav />
                <Routes>
                    <Route path="/" element={<Welcome />} exact />
                    <Route path="/dashboard" element={<Dashboard history={history}/>} exact /> //passes it down to child component
                    <Route path="/createmonthwallet" element={<CreateMonthWallet history={history}/>} exact /> //passes it down to child component
                    <Route path="*" element={<NotFound />} exact />
                </Routes>
            </div>
        </BrowserRouter>
    )
}

What we did here:

  1. Create a history object by importing createBrowserHistory from history. Use 'npm install history' if you do not have it yet.
  2. Defining the variable inside your App function.
  3. Pass it down as 'props' in your Route.

Now, your component will have access to this.props.history and you the error should go away.

As sidenotes, prefer using function components anywere in your code. Much easier to read, write, and much more flexible. Also, avoid using uppercase letters in path. something like path="wallet/month/create" would look more elegant in the long term cause you could have "wallet/month/update", "wallet/month/delete" and so on

  • This likely won't work as expected since it creates a ***new*** history object/context that the `BrowserRouter` isn't aware of. Using the "other" `history` object will update the URL in the address bar but it won't effect routing/UI changes in the `BrowserRouter`. – Drew Reese Dec 28 '22 at 23:19
0

Issue

react-router-dom@6 removed the route props, so there should be some sort of error in the console along the lines of can't access property "push" of undefined when trying to execute this.props.history.push('/Dashboard'). The history object was replaced by a navigate function in RRDv6, accessible via the useNavigate hook.

Solution

You can either convert CreateMonthWallet into a React function component so it can use React hooks, or you can create a custom withRouter Higher Order component to inject the navigate function as a prop.

Convert to React function component

import axios from 'axios'
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';

const CreateMonthWallet  = () => {
  const navigate = useNavigate();

  const [state, setState] = useState({
    name: '',
    accountNumber: '',
    description: '',
    priority: ''
  });

  const changeHandler = (event) => {
    const { name, value } = event.target;
    setState(state => ({
      ...state,
      [name]: value
    }))
  }

  const submitHandler = (event) => {
    event.preventDefault();

    axios.post('http://localhost:8080/monthwallet', state)
      .then((res) => {
        navigate('/Dashboard');
      })
      .catch((err) => {
        alert("Error");
      });
  }

  return (
    <div className="project">
      <div className="container">
        <div className="row">
          <div className="col-md-8 m-auto">
            <h5 className="display-4 text-center">Create Wallet</h5>
            <hr />
            <form onSubmit={submitHandler}>
              <div className="form-group">
                <input
                  type="text"
                  name="name"
                  onChange={changeHandler}
                  className="form-control form-control-lg"
                  placeholder="Account Name"
                  value={state.name}
                />
              </div>
              <div className="form-group">
                <input
                  type="text"
                  name="accountNumber"
                  onChange={changeHandler}
                  className="form-control form-control-lg"
                  placeholder="Account No"
                  value={state.accountNumber}
                />
              </div>
              <div className="form-group">
                <textarea
                  name="description"
                  onChange={changeHandler}
                  className="form-control form-control-lg"
                  placeholder="Description"
                  value={state.description}
                />
              </div>
              <div className="form-group">
                <select
                  className="form-control form-control-lg"
                  name="priority"
                  onChange={changeHandler}
                  value={state.priority}
                >
                  <option value={3}>Display Priority</option>
                  <option value={1}>High</option>
                  <option value={2}>Medium</option>
                  <option value={3}>Low</option>
                </select>
              </div>
              <input
                type="submit"
                className="btn btn-dark btn-block mt-4" value="Create"
              />
            </form>
          </div>
        </div>
      </div>
    </div>
  );
};

export default CreateMonthWallet;

Create withRouter HOC

Follow the instructions at What happened to withRouter? I need it! part of the RRDv6 FAQ to create a replacement withRouter HOC.

Example:

import {
  useLocation,
  useNavigate,
  useParams,
} from "react-router-dom";

const withRouter = Component => props => {
  const location = useLocation();
  const navigate = useNavigate();
  const params = useParams();

  return (
    <Component
      {...props}
      router={{ location, navigate, params }}
    />
  );
}

Decorate the CreateMonthWallet with the new withRouter HOC and access this.props.router.navigate.

class CreateMonthWallet extends Component {
  ...

  submitHandler = (event) => {
    event.preventDefault();
    const newWallet = { ...this.state };

    axios.post('http://localhost:8080/monthwallet', newWallet)
      .then((res) => {
        this.props.router.navigate('/Dashboard');
      })
      .catch((err) => {
        alert("Error")
      });
  }

  render() {
    return (
      ...
    );
  }
}

export default withRouter(CreateMonthWallet);
Drew Reese
  • 165,259
  • 14
  • 153
  • 181