My react app is not redirecting to the dashboard page after submitting a form. I tried using react-router-dom Redirect function but still with no success. I then opt-in for Browser History. push but still no success.
for the latter trial, the URL changes to /dashboard but the component remains on the form page, it doesn't move to dashboard until I reload the page
form field
<form>
<Input
displayValidationErrors={displayValidationErrors("fullname", validators)}
name="fullname"
type="text"
label="Full Name"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("password", validators)}
name="password"
type="password"
label="Password"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("password2", validators)}
name="password2"
type="password"
label="Confirm Password"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("email", validators)}
name="email"
type="email"
label="Email Address"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors(
"phone_number",
validators
)}
name="phone_number"
type="number"
label="Phone Number"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("card_number", validators)}
value={data.card_number}
name="card_number"
type="text"
label="Card Number"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("date", validators)}
value={data.date}
name="date"
type="text"
label="Expiry Date"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<Input
displayValidationErrors={displayValidationErrors("pin", validators)}
name="pin"
type="password"
label="PIN"
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<div className="col-lg-12 loginbttm">
<div className=" login-btm login-button">
<Button
handleClick={onSubmit}
type="submit"
className="btn btn-primary"
label="SUBMIT"
disabled={!isFormValid(validators)}
/>
</div>
</div>
</form>;
onSubmit function
const onSubmit = (e) => {
e.preventDefault();
browserHistory.push("/dashboard");
};
Button Component
const Button = ({ type, className, handleClick, label, disabled }) => (
<button
type={type}
className={className}
onClick={handleClick}
disabled={disabled}
>
{label}
</button>
);
My app.js
function App() {
return (
<Router>
<div className="App">
<Switch>
<Route exact path="/dashboard">
<Dashboard />
</Route>
<Route exact path="/">
<Form />
</Route>
</Switch>
</div>
</Router>
);
}
export default App;
I don't see createBrowserHistory or something like <Router history={history}> so I guess you are using the default browser history. In that case you need withRouter to make it work:
import React from "react";
import { withRouter } from "react-router-dom";
function App() {
const onSubmit = (e) => {
e.preventDefault()
this.props.history.push("/personalInfo");
}
...
}
export default withRouter(App);
More about withRouter solution here
More about createBrowserHistory solution here
For functional component with react-router V5, you can also do with hooks:
import { useHistory } from "react-router-dom";
function App() {
let history = useHistory();
const onSubmit = (e) => {
e.preventDefault()
history.push('/dashboard');
}
return (
<Router>
<div className="App">
...
</div>
</Router>
);
}
Take a look at this to know more about useHistory
try using below. hope it'll help
this.props.history.push({
pathname: '/dashboard'
})
Another way of doing it with the function component -
import {withRouter} from "react-router-dom";
function SignIn({history}) {
const submit = (event) => {
event.preventDefault();
history.push("/profile");
}
....
}
export default withRouter(SignIn)
Related
I have an EditProfile functional component that initially loads perfect, but loses state whenever the user refreshes their page with the form open. Instead of pre-filling the inputs with the 'user' state/values, it now sets the inputs as blank, and the 'user' object from const [user, setUser] = useState({}) console.logs as an empty object.
Here is the EditProfile component:
import React, {useEffect, useState} from 'react'
import './EditProfile.css'
export default function EditProfile(props) {
const [user, setUser] = useState({})
let handleChange = (e) => {
setUser({...user, [e.target.name]: e.target.value})
}
let handleSubmit = async () => {
let body = {
_id: user._id,
email: user.email,
username: user.username,
shortDescription: user.shortDescription,
fullDescription: user.fullDescription,
paymentInfo: user.paymentInfo,
publisherAgreement: user.publisherAgreement
}
let options = {
method: 'PUT',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(body)
}
await fetch('/api/users/editProfile', options)
.then(res => res.json())
.then(data => {
this.props.setUserInState(data)
})
}
useEffect(() => {
(async() => {
setUser(props.user)
})()
},[])
console.log('here is the user: ' + JSON.stringify(user))
return (
<form className='editProfileForm' onSubmit={handleSubmit}>
<input type='hidden' value={user._id}></input>
<input type='hidden' value={user.email}></input>
<div>
<h4>Edit Profile</h4>
<div className="form-group address-update">
<label className="inputUD"><span className="label"><b>Username</b></span></label>
<input type="text" className="form-control" name="username" onChange={handleChange} value={user.username}></input>
</div>
<div className="form-group address-update">
<label className="inputUD"><span className="label"><b>Email</b></span></label>
<input type="text" className="form-control" name="email" onChange={handleChange} value={user.email}></input>
</div>
{user.publisherAgreement &&
<div>
<div className="form-group">
<label className="inputUD"><span className="label"><b>Short Description</b></span></label>
<textarea type="text" className="form-control" name="shortDescription" onChange={handleChange} value={user.shortDescription}></textarea>
</div>
<div className="form-group">
<label className="inputUD"><span className="label"><b>Full Description</b></span></label>
<textarea type="text" className="form-control" name="fullDescription" onChange={handleChange} value={user.fullDescription}></textarea>
</div>
<div className="form-group address-update">
<label className="inputUD"><span className="label"><b>Fake Payment Info</b></span></label>
<input type="text" className="form-control" name="paymentInfo" onChange={handleChange} value={user.paymentInfo}></input>
</div>
</div>
}
<button type="submit" className="btn btn-success">Submit</button>
</div>
</form>
)
}
And here is the App.jsx component where it is called on (I cut out imports to save space):
state = {
user: false,
}
setUserInState = (incomingUserData) => {
console.log('incoming userdata: ' + JSON.stringify(incomingUserData))
this.setState({user: incomingUserData})
}
componentDidMount() {
let token = localStorage.getItem('token')
if (token) {
const payload = JSON.parse(atob(token.split('.')[1]))
if (payload.exp < Date.now() / 1000) {
localStorage.removeItem('token')
token = null
} else {
this.setState({ user: payload.user })
}
}
}
render() {
return (
<div className="App">
<Navbar user={this.state.user} setUserInState={this.setUserInState}/>
<Routes>
<Route path='/ideas/create' element={<NewIdea user={this.state.user} setUserInState={this.setUserInState}/>}/>
<Route path='/users/showProfile' element={<UserProfile user={this.state.user} setUserInState={this.setUserInState}/>}/>
<Route path='/users/editProfile' element={<EditProfile user={this.state.user} setUserInState={this.setUserInState}/>}/>
<Route path='/publishers/becomePublisher' element={<BecomePublisher user={this.state.user} setUserInState={this.setUserInState}/>} />
<Route path='/users/addSubscription'/>
<Route path='/users/removeSubscription'/>
<Route path='/publishers/show/:id' element={<PubProfile user={this.state.user}/>}/>
<Route path='/ideas/show/:id' element={<PubIdeas user={this.state.user}/>}/>
<Route path='/ideas/ideasFeed/:userId' element={<IdeasFeed user={this.state.user}/>}/>
<Route path='/discover/:id' element={<Discover user={this.state.user} setUserInState={this.setUserInState}/>}/>
<Route path='*' element={<Navigate to='/discover/:id' replace />}/>
</Routes>
</div>
)
}
}
The page is accessed via a "Link to" in the Navbar component.
While the form works fine as long as the user doesn't hit refresh, I need the form to be able to handle a refresh and still work.
Any help is much appreciated.
It supposed to add the student list when I click on the button, but it doesn't.
It should be like the pict below:
I already check my code, and here it is:
import React from "react";
import './App.css';
import "antd/dist/antd.css";
import { Form, Input, Button } from "antd";
import Operation from "antd/lib/transfer/operation";
import { PlusCircleOutlined } from '#ant-design/icons';
function App() {
return (
<div className="App">
<h2>Dynamic Form Dengan Validasi</h2>
<form>
<Form.Item name={"teacher"} label="Teacher Name">
<Input placeholder="Teacher Name"></Input>
</Form.Item>
<Form.Item name={"class"} label="Class Name">
<Input placeholder="Class"></Input>
</Form.Item>
<Form.List name={"students"}>
{(fields, {add, remove}) => (
<>
{fields.map((field, index)=>{
return (
<Form.Item name={[field.name,"first"]} label={`${index + 1}-Student`}>
<Input placeholder="First Name"></Input>
</Form.Item>
);
})}
<Form.Item>
<Button icon={<PlusCircleOutlined />} type="dashed" block onClick={() => { add();}}>
Add A Student</Button>
</Form.Item>
</>
)}
</Form.List>
</form>
</div>
);
}
export default App;
I don't know what went wrong, only see the warning in the first pict.
You're missing Form.Provider. You need it in order to use Form
import { FormProvider } from 'react-hook-form';
After that make sure to wrap your <Form> tag with a <FormProvider> tag.
function App() {
return (
<div className="App">
<h2>Dynamic Form Dengan Validasi</h2>
<FormProvider>
<Form>
<Form.Item name={"teacher"} label="Teacher Name">
<Input placeholder="Teacher Name"></Input>
</Form.Item>
<Form.Item name={"class"} label="Class Name">
<Input placeholder="Class"></Input>
</Form.Item>
<Form.List name={"students"}>
{(fields, {add, remove}) => (
<>
{fields.map((field, index)=>{
return (
<Form.Item name={[field.name,"first"]} label={`${index + 1}-Student`}>
<Input placeholder="First Name"></Input>
</Form.Item>
);
})}
<Form.Item>
<Button icon={<PlusCircleOutlined />} type="dashed" block onClick={() => { add();}}>
Add A Student
</Button>
</Form.Item>
</>
)}
</Form.List>
</Form>
</FormProvider>
</div>
);
}
I am building a login and register app using react and on inspec after hitting Sing up I get the error:
Cannot POST /localhost:8000/register
On the console, the following message is displayed:
POST http://localhost:3001/localhost:8000/register 404 (Not Found)
My app.js looks like this:
import 'bootstrap/dist/css/bootstrap.min.css';
import React from 'react';
import { BrowserRouter,Switch,Route } from "react-router-dom";
import './App.css';
import Home from './components/home_component';
import Nav from './components/nav_component';
import Login from './components/login_component';
import Register from './components/register_component';
function App() {
return (
<BrowserRouter>
<div className="App">
<Nav/>
<div className="auth-wrapper">
<div className="auth-inner">
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/login" component={Login}/>
<Route exact path="/register" component={Register}/>
</Switch>
</div>
</div>
</div>
</BrowserRouter>
);
}
export default App;
my register_component.js looks like this:
import React, { Component } from 'react';
import axios from 'axios';
class Register extends Component {
handleSubmit = e => {
e.preventDefault();
const data = {
first_name: this.firstName,
last_name: this.lastName,
email: this.email,
password: this.password,
password_confirm: this.confirmPassword
};
axios.post('http:/localhost:8000/register', data).then(
res =>{
console.log(res);
}
).catch(err =>{
console.log(err);
})
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<h3>Sign Up</h3>
<div className="form-group">
<label>First Name</label>
<input type='text' className='form-control' placeholder='First Name' onChange={e => this.firstName = e.target.value}/>
</div>
<div className="form-group">
<label>Last Name</label>
<input type='text' className='form-control' placeholder='Last Name' onChange={e => this.lastName = e.target.value}/>
</div>
<div className="form-group">
<label>Email</label>
<input type='email' className='form-control' placeholder='Email' onChange={e => this.email = e.target.value}/>
</div>
<div className="form-group">
<label>Password</label>
<input type='password' className='form-control' placeholder='Password'onChange={e => this.password = e.target.value}/>
</div>
<div className="form-group">
<label>Confirm Password</label>
<input type='password' className='form-control' placeholder=' Confirm Password' onChange={e => this.confirmPassword = e.target.value}/>
</div>
<button className='btn btn-primary btn-block'>Sign Up</button>
</form>
);
}
}
export default Register;
You have give the link wrong in your code
axios.post('http:/localhost:8000/register', data).then(
It should be
axios.post('http://localhost:8000/register', data).then(
You are missing a forward slash
I have an react app Form component split into Login and Signup forms. It is supposed to render the Signup by default but switch to Login if login is button is clicked. When login button is clicked, the page switches to the Login form very briefly before switching back to the Signup form. I don't know what is causing this. I have tried placing const [page, setPage] = setState("signup") in the parent App and passing setPage as a prop along with page. This produced the same results. I believe this issue is similar to this one but that was not resolved.
Here is the app:
import Form from "./components/Signup-Form.js";
function App() {
return (
<div className="App">
<h1>Welcome</h1>
<Form />
</div>
);
}
export default App;
and Signup-Form.js:
import React from "react";
import { useState, useEffect } from "react";
import "./Forms.css";
import { InputField, Buttons } from "./Inputs";
function Form() {
const [page, setPage] = useState("signup");
const pageLabel = page;
let Signup = () => {
function toLogin() {
setPage("login");
}
return (
<form action="" method="get" className="form">
<div className="input-container">
<InputField name="Company Name" id="comp-name" type="text" />
<InputField name="Company ID" id="comp-id" type="text" />
<InputField name="Username" id="username" type="text" />
<InputField name="Email" id="email" type="email" />
<InputField name="Password" id="password" type="password" />
<InputField name="Confirm Password" id="confirm-password" type="password" />
</div>
<div className="btns">
<Buttons name="Sign Up" id="signup-btn" type="submit" cls="success" />
<Buttons name="Log In" id="login-btn" type="button" cls="success" alt="true" onClick={toLogin} />
</div>
</form>
);
};
let Login = () => {
function toSignup() {
setPage("signup");
}
return (
<form action="" method="get" className="form">
<div className="input-container">
<InputField name="Company ID" id="comp-id" type="text" />
<InputField name="Password" id="password" type="password" />
</div>
<div className="btns">
<Buttons name="Log In" id="login-btn" type="submit" cls="success" />
<Buttons name="Sign Up" id="signup-btn" type="submit" cls="success" alt onClick={toSignup} />
</div>
</form>
);
};
let form = (formType) => (
<div className="outer-wrapper">
<div className="form-wrapper">
<label className="form-title">{pageLabel}</label>
{formType}
</div>
</div>
);
if (page === "signup") {
const signup = Signup();
return form(signup);
} else if (page === "login") {
const login = Login();
return form(login);
}
}
export default Form;
The reason why after you click on Login button and get Login page and the page immediately re-renders and you get the Signup page is conditional render in your example. Right after clicking on Login button your state still previous and for this reason after click you get the main (Signup) page.
Suggest to change the structure render into smth like this:
...
return (
<div className="outer-wrapper">
<div className="form-wrapper">
<label className="form-title">{pageLabel}</label>
{page === "signup" && Signup()}
{page === "login" && Login()}
</div>
</div>
);
Here is the example in an action - https://codesandbox.io/s/smoosh-water-6jj18?file=/src/App.js
My App Component is here
import React, { useEffect } from 'react';
import './App.css';
import Navbar from './components/layout/Navbar';
import Landing from './components/layout/Landing';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Login from './components/auth/Login';
import Register from './components/auth/Register';
import { Provider } from 'react-redux';
import store from './store';
import Alert from './components/layout/Alert';
import setAuthToken from './utils/setAuthToken';
import { loadUser } from './actions/auth';
import Dashboard from './components/dashboard/Dashboard';
import PrivateRoute from './components/routing/PrivateRoute';
import CreateProfile from './components/profile-form/CreateProfile';
import EditProfile from './components/profile-form/EditProfile';
import AddExperience from './components/profile-form/AddExperience';
import AddEducation from './components/profile-form/AddEducation';
if (localStorage.token) {
setAuthToken(localStorage.token);
}
const App = () => {
useEffect(() => {
store.dispatch(loadUser());
}, []);
return (
<Provider store={store}>
<Router>
<>
<Navbar />
<Route exact path='/' component={Landing} />
<section className='container'>
<Alert />
<Switch>
<Route exact path='/login' component={Login} />
<Route exact path='/register' component={Register} />
<PrivateRoute exact path='/dashboard' component={Dashboard} />
<PrivateRoute
exact
path='/create-profile'
component={CreateProfile}
/>
<PrivateRoute
exact
path='/edit-profile'
component={EditProfile}
/>
<PrivateRoute
exact
to='/add-experience'
component={AddExperience}
/>
<PrivateRoute
exact
path='/add-education'
component={AddEducation}
/>
</Switch>
</section>
</>
</Router>
</Provider>
);
};
export default App;
My AddExperience Component is here
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { addExperience } from '../../actions/profile';
import { Link, withRouter } from 'react-router-dom';
const AddExperience = ({ addExperience, history }) => {
const [formData, setFormData] = useState({
company: '',
title: '',
location: '',
from: '',
to: '',
current: false,
description: '',
});
const [toDateDisabled, toggleDisabled] = useState(false);
const { company, title, location, from, to, current, description } = formData;
const onChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
return (
<>
<h1 className='large text-primary'>Add An Experience</h1>
<p className='lead'>
<i className='fas fa-code-branch'></i> Add any developer/programming
positions that you have had in the past
</p>
<small>* = required field</small>
<form
className='form'
onSubmit={(e) => {
e.preventDefault();
addExperience(formData, history);
}}
>
<div className='form-group'>
<input
type='text'
placeholder='* Job Title'
name='title'
value={title}
onChange={(e) => onChange(e)}
required
/>
</div>
<div className='form-group'>
<input
type='text'
placeholder='* Company'
name='company'
value={company}
onChange={(e) => onChange(e)}
required
/>
</div>
<div className='form-group'>
<input
type='text'
placeholder='Location'
name='location'
value={location}
onChange={(e) => onChange(e)}
/>
</div>
<div className='form-group'>
<h4>From Date</h4>
<input
type='date'
name='from'
value={from}
onChange={(e) => onChange(e)}
/>
</div>
<div className='form-group'>
<p>
<input
type='checkbox'
name='current'
checked={current}
value={current}
onChange={(e) => {
setFormData({ ...formData, current: !current });
toggleDisabled(!toDateDisabled);
}}
/>{' '}
Current Job
</p>
</div>
<div className='form-group'>
<h4>To Date</h4>
<input
type='date'
name='to'
value={to}
onChange={(e) => onChange(e)}
disabled={toDateDisabled ? 'disable' : ''}
/>
</div>
<div className='form-group'>
<textarea
name='description'
cols='30'
rows='5'
placeholder='Job Description'
value={description}
onChange={(e) => onChange(e)}
></textarea>
</div>
<input type='submit' className='btn btn-primary my-1' />
<a className='btn btn-light my-1' href='dashboard.html'>
Go Back
</a>
</form>
</>
);
};
AddExperience.propTypes = {
addExperience: PropTypes.func.isRequired,
};
export default connect(null, { addExperience })(AddExperience);
Here is my AddEducation Component
import React, { useState, Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { addEducation } from '../../actions/profile';
import { Link, withRouter } from 'react-router-dom';
const AddEducation = ({ addEducation, history }) => {
const [formData, setFormData] = useState({
school: '',
degree: '',
fieldofstudy: '',
from: '',
to: '',
current: false,
description: '',
});
const [toDateDisabled, toggleDisabled] = useState(false);
const {
school,
degree,
fieldofstudy,
from,
to,
current,
description,
} = formData;
const onChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
return (
<Fragment>
<h1 className='large text-primary'>Add Your Education</h1>
<p className='lead'>
<i className='fas fa-code-branch'></i> Add any School or bootcamp that
you have attended
</p>
<small>* = required field</small>
<form
className='form'
onSubmit={(e) => {
e.preventDefault();
addEducation(formData, history);
}}
>
<div className='form-group'>
<input
type='text'
placeholder='* School or Bootcamp'
name='school'
value={school}
onChange={(e) => onChange(e)}
required
/>
</div>
<div className='form-group'>
<input
type='text'
placeholder='* Degree or Certificate'
name='degree'
value={degree}
onChange={(e) => onChange(e)}
required
/>
</div>
<div className='form-group'>
<input
type='text'
placeholder='fieldofstudy'
name='fieldofstudy'
value={fieldofstudy}
onChange={(e) => onChange(e)}
/>
</div>
<div className='form-group'>
<h4>From Date</h4>
<input
type='date'
name='from'
value={from}
onChange={(e) => onChange(e)}
/>
</div>
<div className='form-group'>
<p>
<input
type='checkbox'
name='current'
checked={current}
value={current}
onChange={(e) => {
setFormData({ ...formData, current: !current });
toggleDisabled(!toDateDisabled);
}}
/>{' '}
Current Job
</p>
</div>
<div className='form-group'>
<h4>To Date</h4>
<input
type='date'
name='to'
value={to}
onChange={(e) => onChange(e)}
disabled={toDateDisabled ? 'disable' : ''}
/>
</div>
<div className='form-group'>
<textarea
name='description'
cols='30'
rows='5'
placeholder='Programme Description'
value={description}
onChange={(e) => onChange(e)}
></textarea>
</div>
<input type='submit' className='btn btn-primary my-1' />
<a className='btn btn-light my-1' href='dashboard.html'>
Go Back
</a>
</form>
</Fragment>
);
};
AddEducation.propTypes = {
addEducation: PropTypes.func.isRequired,
};
export default connect(null, { addEducation })(AddEducation);
And Lastly here is the DashboardActions Component
import React from 'react';
import { Link } from 'react-router-dom';
const DashboardActions = () => {
return (
<div className='dash-buttons'>
<Link to='/edit-profile' className='btn btn-light'>
<i className='fas fa-user-circle text-primary' /> Edit Profile
</Link>
<Link to='/add-experience' className='btn btn-light'>
<i className='fab fa-black-tie text-primary' /> Add Experience
</Link>
<Link to='/add-education' className='btn btn-light'>
<i className='fas fa-graduation-cap text-primary' /> Add Education
</Link>
</div>
);
};
export default DashboardActions;
The Problem is When i Click on AddExperience it opens correctly with correct url but when i click on AddEducation it Opens the same Add Experience Form but url changed Correctly.
There is a typo here:
<PrivateRoute
exact
to='/add-experience'
component={AddExperience}
/>
The 'to' should be replaced with 'path'