How to navigate to another page in reactJS using SubmitHandler? - reactjs

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>
)
}

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);

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:
Create a history object by importing createBrowserHistory from history. Use 'npm install history' if you do not have it yet.
Defining the variable inside your App function.
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

Related

react-router-dom how to redirect after button click in component

I have login component and after user singin i will got data from express server with fetch that will say all okay i want to redirect user to main page.I didn't find anything that i may use with react-router-dom to redirect user. First thing i want to now,is redirect user after he click button, without data check
this is how my Routes
ReactDOM.render(
<div>
<div><div className="nav">
<BrowserRouter>
<div className="shapka">
<Link to={linkToLogin} className="login">Войти в профиль</Link>
</div>
<div className="navItems">
<Link to='/Rings' className="navItem">Кольца</Link>
<Link to='/Earrings' className="navItem">Серёжки</Link>
<Link to='/' className="navItem">Главная страница</Link>
<Link to='/Bracelets' className="navItem">Браслеты</Link>
<Link to='/Necklace' className="navItem">Ожерелья</Link>
</div>
<Routes>
<Route path="/" element={<App/>}/>
<Route path="/Rings" element={<Rings/>}/>
<Route path="/EarRings" element={<EarRings/>}/>
<Route path="/bracelets" element={<Bracelets/>}/>
<Route path="/Necklace" element={<Necklase/>}/>
<Route path='/Profile' element={<Login/>}/>
<Route path="Register" element={<Register/>}/>
</Routes>
</BrowserRouter>
</div>
</div>
</div>,
document.getElementById('mainDiv')
);
and this is my component that located in other js file
login.addEventListener('click',e=>{
let login = document.getElementById('username')
let pwd = document.getElementById('password')
if(login.value !== '' && pwd.value !== ''){
sendToLogin({login:login.value,pwd:pwd.value})
}
})
}
render(){
return <div className="main" id="main">
<div className="registration-cssave">
<div className="form" >
<h3 className="text-center">Вход в систему</h3>
<div className="form-group">
<input className="form-control item" type="text" name="login" maxLength="15" id="inputLogin" minLength="4"
pattern="^[a-zA-Z0-9_.-]*$" id="username" placeholder="Логин" required />
</div>
<div className="form-group">
<input className="form-control item" type="password" name="password" minLength="6" id="password"
placeholder="Пароль" required/>
</div>
<div className="form-group">
<button className="btn btn-primary btn-block create-account" type="submit" id="btnEnter">Войти</button>
</div>
<div className="toRegister">
<a href="/Register" >Регистрация</a>
</div>
</div>
</div>
</div>
}
}
export default Login
You can use the useHistory hook from react-router-dom
import { useHistory } from 'react-router-dom';
function App () {
const history = useHistory();
async function logUser (userData) {
const res = await api.post("yourApi/login",{data});
if(res.status===200){
history.push("/");
}
}
render(
// Rendered parts
)
}
Additionally you can render a hidden Link component with display: "none", attach it to a ref and programmatically click it when the server response is okay. Like this:
const redirectToMain = useRef(null);
async function logUser (userData) {
const res = await api.post("yourApi/login",{data});
if(res.status===200){
redirectToMain.current.click()
}
}
render (
// *** other parts
<Link
to="/"
ref={redirectToMain}
style={{display: "none"}}
/>
)
for class components, at the first you should make a functional component then use HOC technical to use useNavigate react hook. like this:
withrouter.js:
import {useNavigate} from 'react-router-dom';
export const withRouter = WrappedComponent => props => {
return (<WrappedComponent {...props} navigate={useNavigate()}/>);
};
then use use it in other class components like this:
export default withRouter(Signin);
and use props for redirect like this:
this.props.navigate('/');

onSubmit button not redirecting to Profile component page

So I want my submit button from Signup to direct me to my Profile page in my react app. But I cannot get it to work with the suggestions given online. I would like to know what my errors are in my code.
I want to be able to click the Sign Up button and be able to get to the /profile route of my application. I am not sure why it doesn't work and it doesnt show any errors anywhere, it just goes to my Express POST route at the moment.
sign-up.component.js
import React, { Component } from "react";
import { Redirect } from 'react-router';
import { withRouter } from 'react-router';
export default class SignUp extends Component {
constructor(props){
super(props)
this.state = {
firstName: '',
lastName: '',
email: '',
}
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
}
onSubmit = (e) => {
e.preventDefault();
const {firstName, lastName, email} = this.state;
fetch('http://localhost:9000/users/new', {
method: "POST",
headers: {
'Content-Type' : 'application/json'
},
body: JSON.stringify(this.state)
})
.then((result) => result.json())
.then((info) => {console.log(info)})
this.props.history.push('/profile'); }
render() {
return (
<form method='POST' action='http://localhost:9000/users/new'>
<h3>Sign Up</h3>
<div className="form-group">
<label>First name</label>
<input type="text" className="form-control" placeholder="First name" name ="firstName"/>
</div>
<div className="form-group">
<label>Last name</label>
<input type="text" className="form-control" placeholder="Last name" name="lastName" />
</div>
<div className="form-group">
<label>Email address</label>
<input type="email" className="form-control" placeholder="Enter email" name="email" />
</div>
<div className="form-group">
<label>Password</label>
<input type="password" className="form-control" placeholder="Enter password" />
</div>
<button type="submit" className="btn btn-primary btn-block" onClick={this.onSubmit}>Sign Up</button>
<p className="forgot-password text-right">
Already registered sign in?
</p>
</form>
);
}
App.js
import React from 'react';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import './App.css';
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Login from "./components/login.component";
import SignUp from "./components/sign-up.component";
import Profile from "./components/profile";
function App() {
return (<Router>
<div className="App">
<nav className="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div className="container">
<Link className="navbar-brand" to={"/sign-in"}>Code Process Reviews</Link>
<div className="collapse navbar-collapse" id="navbarTogglerDemo02">
<ul className="navbar-nav ml-auto">
<li className="nav-item">
<Link className="nav-link" to={"/sign-in"}>Login</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to={"/sign-up"}>Sign up</Link>
</li>
</ul>
</div>
</div>
</nav>
<div className="auth-wrapper">
<div className="auth-inner">
<Switch>
<Route exact path='/' component={Login} />
<Route path="/sign-in" component={Login} />
<Route path="/sign-up" component={SignUp} />
<Route path="/profile" component={Profile} />
</Switch>
</div>
</div>
</div></Router>
);
}
export default App;
you cannot use this in arrow functions change the arrow syntax to normal
from onSubmit(e)=>{} to function onSubmit(e){}
Instead of using history.push set state flag for redirection
e.g
this.state = {
...
url: '',
}
....
// After network response
this.setState({url: '/profile'});
// And in Component
{ this.state.url ? <Redirect to={this.state.url} /> : null }

how to redirect back to App with React.js from a component?

i'm new learner of React.js and i don't finding the right solution.
i have the CreateUser component and when a client success at creating one i want to Redirect the client to App...
i need it to happend in this function of CreateUser Component
private handleSubmit(e:any){
e.preventDefault();
this.setState({
username: this.state.username,
password: this.state.password,
confirmPassword: this.state.confirmPassword,
userEmail: this.state.userEmail
})
this.passConfrim();
if (this.isAlertVisible){
console.log(this.state)
this.myUserDateService.create(this.state);
----> ** Right Here i need to redirect! ** <----
}
}
in the end of the function at the if statement
App:
import './App.css';
import { LoginComponent } from './components/LoginComponent';
import CreateUser from './components/CreateUser';
import "bootstrap/dist/css/bootstrap.min.css";
import { Router, Switch, Route, Link, useHistory as history} from "react-router-dom";
function App() {
return (
<Router history={history()} >
<nav className="navbar navbar-expand navbar-dark bg-dark">
<a href="/Home" className="navbar-brand">
To Do List
</a>
<div className="navbar-nav mr-auto">
<li className="nav-item">
<Link to={"/Login"} className="nav-link">
Login
</Link>
</li>
<li className="nav-item">
<Link to={"/CreateUser"} className="nav-link">
Create User
</Link>
</li>
</div>
</nav>
<div id="App-content">
<Switch >
<Route exact path={["/", "/Home"]} />
<Route path="/Login" exact component={LoginComponent} />
<Route path="/CreateUser" exact component={CreateUser} />
</Switch>
</div>
</Router>
);
}
export default App;
CreateUser Component:
import React, { Component } from 'react';
import { UserDataService } from '../services/UserData.service';
interface IState {
username:string;
userEmail:string;
password:string;
confirmPassword:string;
}
export class CreateUser extends Component <{}, IState> {
isAlertVisible: boolean = true;
myUserDateService = new UserDataService();
constructor(props: {}, myUserDateService:UserDataService){
super(props );
this.state = {
username:"",
password:"",
confirmPassword:"",
userEmail:"",
}
}
private handleSubmit(e:any){
e.preventDefault();
this.setState({
username: this.state.username,
password: this.state.password,
confirmPassword: this.state.confirmPassword,
userEmail: this.state.userEmail
})
this.passConfrim();
if (this.isAlertVisible){
console.log(this.state)
this.myUserDateService.create(this.state);
}
}
passConfrim(){
if(this.state.password !== this.state.confirmPassword){
this.isAlertVisible = false;
}else{
this.isAlertVisible = true;
}
}
render() {
return (
<div className="form-group">
<h1>Create User</h1>
<form onSubmit={e => this.handleSubmit(e)}>
<label >Username</label>
<input className="form-control" type="text" placeholder='Enter Username...' onChange={e => this.setState({username : e.target.value})} required/>
<br/>
<label >Email</label>
<input className="form-control" type="text" placeholder='Enter your email...' onChange={e => this.setState({userEmail : e.target.value})} required/>
<br/>
<label >Passowrd</label>
<input className="form-control" type="password" placeholder='Enter Password...' onChange={e => this.setState({password : e.target.value})} required/>
<br/>
<label >Confirm Passowrd</label>
<input className="form-control" type="password" placeholder='Confirm Password...' onChange={e => this.setState({confirmPassword : e.target.value })} required />
<div style={{color: "red", textAlign: "left"}} hidden={this.isAlertVisible}>**password not match</div>
<br/>
<button className="btn btn-primary" type="submit" >Create User</button>
</form >
</div>
)
}
}
export default CreateUser;
Basically you need not pass history with Router instead you can use withRouter high order component from react-router.
Import withRouter inside createUser component - https://reacttraining.com/react-router/core/api/withRouter
import { withRouter } from "react-router";
Then we just need to export CreateUser component like -
export default withRouter(CreateUser);
Now you have access to all props related to routing inside CreateUser component, now you can use -
this.props.history.push('/your-route');
To check what else properties you have with withRouter, you can just console.log this.props.history inside CreateUser component.
Tip - You cannot use hooks inside class components, so you cannot use useHistory inside CreateUser component instead use withRouter.
you can use history.push('/yourRoute') and that will take you to whatever route your heart so desires
Since you are extending the user component from react, it is a class component and you cannot use 'useHistory' hooks inside it.
Also you are passing history as a prop to router, can you try the below code to navigate and let me know.
this.props.history.push('/yourroute');

Apollo 2.1, Mutation and React-Router

I am pretty new to Apollo and starting right with version 2.1.
I also use react-router but I don't know how to do a browserHistory.push after a mutation was completed. Here are parts of my code:
index.js
const client = new ApolloClient({
uri: "http://localhost:4000/graphql"
});
ReactDOM.render(
<ApolloProvider client={client}>
<AppContainer>
<BrowserRouter basename={basename}>
<I18nextProvider i18n={i18n}>
<Layout />
</I18nextProvider>
</BrowserRouter>
</AppContainer>
</ApolloProvider>,
document.getElementById('react_root')
)
};
In onCompleted I want to show a different page to tell user to check the emails. But I don't know how to do so.
RegistrationForm.js
import {browserHistory) from 'react-router';
const onCompleted = (data) => {
browserHistory.push("/de/register/check-email");
}
const RegistrationForm = () => {
return (
<Mutation mutation={REGISTER_USER}
onCompleted={onCompleted}
>
{(register, { data }) => (
<div>
<Form
onSubmit={onSubmit}
render={({ handleSubmit, pristine, invalid, values, variables }) => (
<form onSubmit={(e, ) => {
e.preventDefault();
register({
variables: {
input: {
username: values.username,
email: values.email,
password: values.password
}
}
});
}}
>
<div>
<label>Username</label>
<Field name="username" component="input" placeholder="Username" />
</div>
<div>
<label>Email</label>
<Field name="email" component="input" placeholder="Email" />
</div>
<div>
<label>Password</label>
<Field name="password" component="input" placeholder="Password" />
</div>
<button type="submit" >Submit</button>
</form>
)}
/>
</div>
)}
</Mutation>
);
};
Does anybody knows how to do so? Thanks a lot for your help.
Best regards
There's no export browserHistory in react-router, but there is a history prop.
If your component is immediately under a <Route>, you can use it like this:
const RegistrationForm = ({history}) => {
const onCompleted = (data) => {
history.push("/de/register/check-email");
}
return (
..
If your component is deeper in the tree, you can inject the history and other route props with withRouter, e.g.:
const RegistrationFormWrapped = withRouter(RegistrationForm);
or
export default withRouter(RegistrationForm);
And because onCompleted depends on a prop now and needs to be local, it makes sense to convert RegistrationForm to a class.
I think I found the solution. I passed history as a prop from the calling component and then went with:
const RegistrationFinalForm = ({ history }) => {
return (
<Mutation mutation={REGISTER_USER}
onCompleted={(data) => {
history.push("/de/register/check-email");
}}>

How to add error information empty field and redirect after login in ReactJS and Firebase?

I use react js, react-router, and firebase database. and I want to add error information if login field is empty and if success I want to redirect to dashboard, but it doesn't work
this code in router.js
<Route path="/" name="Home" component={Simple}>
<IndexRoute component={Login}/>
</Route>
<Route path="/dashboard" name="Home" component={Full}>
<IndexRoute component={Dashboard}/>
<Route path="/dashboard" name="Dashboard" component={Dashboard}/>
</Route>
this code in login.js
function setErrorMsg(error) {
return {
loginMessage: error
}
}
class Login extends Component {
state = { loginMessage: null }
handleSubmit = (e) => {
e.preventDefault()
login(this.email.value, this.password.value)
.catch((error) => {
this.setState(setErrorMsg('Invalid username/password.'))
})
}
resetPassword = () => {
resetPassword(this.email.value)
.then(() => this.setState(setErrorMsg(`Password reset email sent to ${this.email.value}.`)))
.catch((error) => this.setState(setErrorMsg(`Email address not found.`)))
}
render() {
return (
<h1>Login</h1>
<form onSubmit={this.handleSubmit}>
<div className="input-group mb-3">
<span className="input-group-addon"><i className="icon-user"></i></span>
<input type="text" ref={(email) => this.email = email} className="form-control" placeholder="Email"/>
</div>
<div className="input-group mb-4">
<span className="input-group-addon"><i className="icon-lock"></i></span>
<input type="password" ref={(password) => this.password = password} className="form-control" placeholder="Password"/>
</div>
{
this.state.loginMessage &&
<div>
<span className="sr-only">Error:</span>
{this.state.loginMessage} Forgot Password?
</div>
}
<button type="button" className="btn btn-primary px-4">Login</button>
<button type="button" className="btn btn-link px-0">Forgot password?</button>
</form>
);
}
}
Quick thought is that you need to bind your onSubmit, like <form onSubmit={this.handleSubmit.bind(this)}>.
Using class ... extends doesn't do autobinding.
Another way I like to do it is to bind in my contructor function:
class Login extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
// your code here
}

Resources