React setState hook keeps resetting and rendering the page twice - javascript

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

Related

How to pass useState state to another component?

There are two components
WelcomePage.jsx
import { useState } from "react";
import SignUpPage from "./SignUpPage";
function WelcomePage() {
const [signUp, toSignUp] = useState(false);
function signUpClick() {
toSignUp(true);
}
return (
<div>
{signUp ? (
<SignUpPage isOpen={signUp} />
) : (
<div
className="Welcome_page__container animate__animated animate__fadeIn"
id="welcome_page"
>
<h1 className="Welcome_page__title">Welcome to Hotel Review </h1>
<h3 className="Welcome_page__subtitle">Sign in :</h3>
<div className="Welcome_page__wrapper">
<label className="Welcome_page__input-title" htmlFor="welcome_mail">
E-mail:
</label>
<input
className="Welcome_page__input"
id="welcome_mail"
type="mail"
placeholder="Your e-mail..."
/>
<label className="Welcome_page__input-title" htmlFor="welcome_pass">
Password:
</label>
<input
className="Welcome_page__input"
id="welcome_pass"
type="text"
placeholder="Your password..."
/>
<button className="Welcome_page__btn">Login</button>
<button className="Welcome_page__btn" onClick={signUpClick}>
Sign Up
</button>
</div>
</div>
)}
</div>
);
}
export default WelcomePage;
SignUpPage.jsx
function SignUpPage() {
return (
<div className="Welcome_page__container animate__animated animate__fadeIn">
<button>Back...</button>
<h1 className="Welcome_page__title">Welcome to Hotel Review </h1>
<h3 className="Welcome_page__subtitle">Sign up :</h3>
<div className="Welcome_page__wrapper">
<label className="Welcome_page__input-title" htmlFor="welcome_mail">
E-mail:
</label>
<input
className="Welcome_page__input"
id="welcome_mail"
type="mail"
placeholder="Your e-mail..."
/>
<label className="Welcome_page__input-title" htmlFor="welcome_pass">
Password:
</label>
<input
className="Welcome_page__input"
id="welcome_pass"
type="text"
placeholder="Your password..."
/>
<label
className="Welcome_page__input-title"
htmlFor="welcome_pass"
></label>
<input
className="Welcome_page__input"
id="welcome_pass_repeat"
type="text"
placeholder="Repeat password..."
/>
<button className="Welcome_page__btn_2">Sign Up</button>
</div>
</div>
);
}
export default SignUpPage;
Clicking the "Sign Up" button in WelcomePage.jsx using useState navigates to SignUpPage.jsx
Question - How can I return back to WelcomePage.jsx on the "Back" button (I understand that I need to return false back to const [signUp, toSignUp] = useState() , but I don't know how to transfer state from WelcomePage to SignUpPage and vice versa.)
You can pass it via props from parent to child component.
And pass the setState from child component to parent.
import { useState } from "react";
import SignUpPage from "./SignUpPage";
function WelcomePage() {
const [signUp, setSignUp] = useState(false);
function signUpClick() {
toSignUp(true);
}
return (
<>
{signUp ? (
<SignUpPage isOpen={signUp} setOpen={setSignUp} />
) : (
<div>
... component
</div>
)
</>
);
}
export default WelcomePage;
function SignUpPage(props) {
const { isOpen, setOpen } = props;
return (
<>
{isOpen}
<button onClick={setOpen(true)}>Open</button>
<button onClick={setOpen(false)}>Close</button>
</>
);
}
export default SignUpPage;

When ever I submit my form I get the form data in my URL instead of it posting to my backend

I am having an issue when I submit my form it puts all of the form data into my URL instead of sending it to my backend. I'm not sure what the issue is at first I thought it was because I didn't have a method="post" in the form tag but that didn't fix my issue because it tried to send the form data to localhost:3000/register instead of localhost:5000/register. Any help would be appreciated.
Bellow is my current Frontend code.
import { BrowserRouter as Router, Route, Routes, Link } from 'react-router-dom'
import '../css/register.css';
import {IoMdArrowRoundBack} from 'react-icons/io'
import { useState } from 'react'
import axios, { Axios } from 'axios';
const Register = () => {
const [emailReg, setEmailReg] = useState("");
const [usernameReg, setUsernameReg] = useState("");
const [passwordReg, setPasswordReg] = useState("");
const register = () => {
Axios.post('http://localhost:5000/register', {
email: emailReg,
username: usernameReg,
password: passwordReg,
}).catch(function (error) {
console.log(error);
});
};
return (
<div className='background-image'>
<div className='back-button'>
<Link to='/'>
<IoMdArrowRoundBack id='back-arrow' />
<h3>Home</h3>
</Link>
</div>
<div className="container-wrapper">
<div className="container">
<h1>Create Account</h1>
<div className="wrapper">
<form>
<div className="textarea" id="email">
<input
type="email"
onChange={(e) => {
setEmailReg(e.target.value);
}}
name="email"
id="authentactor-email"
placeholder="Email"
defaultValue=""
required
/>
</div>
<div className="textarea" id="username">
<input
type="text"
onChange={(e) => {
setUsernameReg(e.target.value);
}}
name="name"
id="authentactor-text"
placeholder="Username"
defaultValue=""
required
/>
</div>
<div className="textarea" id="password">
<input
type="password"
onChange={(e) => {
setPasswordReg(e.target.value);
}}
name="password"
id="authentactor-password"
placeholder="Password"
defaultValue=""
required
/>
</div>
<div id="button-wrapper">
<button id="button" onClick={register}>Create Account</button>
</div>
</form>
<div className='bottom-text-wrapper'>
<h4>Already have an account? <Link to='/login'>Login Here</Link></h4>
</div>
</div>
</div>
</div>
</div>
)
}
export default Register
According to HTML Living Standard
The missing value default and invalid value default are the Submit Button state.
You can find more information on this question but basically adding type="button" to your Create Account button should do the job.
(so something like <button id="button" type="button" onClick={register}>Create Account</button>)
I figured it out for some reason I can't have the "name" tag in my input fields like it is below.
<div className="textarea" id="password">
<input
type="password"
onChange={(e) => {
setPasswordReg(e.target.value);
}}
name="password"
id="authentactor-password"
placeholder="Password"
defaultValue=""
required
/>
</div>
<div id="button-wrapper">
<button onClick={register} id="button">Create Account</button>
</div>
As soon as I removed the "name" tags I was able to POST my form to the backend and I only get a question mark in my url now instead of all the form data. To fix the question mark I had to set button type="button".
correct code below.
<div className="textarea" id="password">
<input
type="password"
onChange={(e) => {
setPasswordReg(e.target.value);
}}
id="authentactor-password"
placeholder="Password"
defaultValue=""
required
/>
</div>
<div id="button-wrapper">
<button type="button" onClick={register} id="button">Create Account</button>
</div>

React + EmailJS is sending me tons of emails in onClick method

I'm new to web development in general but I'm trying to create my own Contact page on my website and I'm having trouble. I'm using React, Gatsby, and Emailjs. I have my form set up so that the inputs are passed into the state onChange. Then I have a "send message" button that should send an email using EmailJS using the tokens and the state vars. This does all work and the email sends successfully, but it's sending dozens of emails. I believe what's happening is it's calling sendEmail every time the state is set and the DOM re-renders, or basically once for each character that's input into the fields, but I don't know why.
Bonus points if you can help me figure out why pressing the send message button also sends me to a 404 /# route on my site.
import React from 'react'
import emailjs from 'emailjs-com
class Main extends React.Component {
constructor(){
super()
this.state = {
fromName:'',
message:'',
fromEmail:''
}
}
render() {
return (
<div ...
>
...
<article>
...
<form method="post" action="#">
<div className="field half first">
<label htmlFor="name">Name</label>
<input type="text" name="name" id="name" value={this.state.fromName} onChange={e => this.setState({fromName: e.target.value})}/>
</div>
<div className="field half">
<label htmlFor="email">Email</label>
<input type="text" name="email" id="email" value={this.state.fromEmail} onChange={e => this.setState({fromEmail: e.target.value})}/>
</div>
<div className="field">
<label htmlFor="message">Message</label>
<textarea name="message" id="message" rows="4" value={this.state.message} onChange={e => this.setState({message: e.target.value})}
placeholder = "..."></textarea>
</div>
<ul className="actions">
<li>
<input type="submit" value="Send Message" className="special" onClick={this.sendEmail()}/>
</li>
</ul>
</form>
</article>
</div>
)
}
sendEmail() {
const serviceId='...'
const templateId='...'
const userId='...'
emailjs.send(serviceId, templateId, this.state, userId)
}
}
export default Main
The issue is that you never followed the emailjs documentation well and you never prevented the default form action.
According to the emailjs documentation you should have set the onClick function with the send email function (without invoking it) on the form's opening tag NOT on your submit button. (but the button is still necessary so that it can send the sign that the form needs to be submitted). You also invoked the sendEmail function which is inappropriate and leads to problems.
You must also add event as a parameter in your sendEmail function when creating this function. Then inside the sendEmail function call the event.preventDefault() function .
import React from 'react'
import emailjs from 'emailjs-com
class Main extends React.Component {
constructor(){
super()
this.state = {
fromName:'',
message:'',
fromEmail:''
}
}
render() {
return (
<div>
<article>
<form method="post" onClick={this.sendEmail} action="#">
<div className="field half first">
<label htmlFor="name">Name</label>
<input type="text" name="name" id="name" value={this.state.fromName} onChange={e => this.setState({fromName: e.target.value})}/>
</div>
<div className="field half">
<label htmlFor="email">Email</label>
<input type="text" name="email" id="email" value={this.state.fromEmail} onChange={e => this.setState({fromEmail: e.target.value})}/>
</div>
<div className="field">
<label htmlFor="message">Message</label>
<textarea name="message" id="message" rows="4" value={this.state.message} onChange={e => this.setState({message: e.target.value})}
placeholder = "..."></textarea>
</div>
<ul className="actions">
<li>
<input type="submit" value="Send Message" className="special"/>
</li>
</ul>
</form>
</article>
</div>
)
}
sendEmail(event) {
event.preventDefault();
const serviceId='...'
const templateId='...'
const userId='...'
emailjs.send(serviceId, templateId, this.state, userId)
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
}
}
export default Main

Redirect to Component onSubmit

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)

How to go from one page to another

I have a SignIn form and I want to create the SignUp link.
On link click I want to open SignUp page.
I have created index.js nothing in that another app.js I wrote SignIn logic.
Here is the Code :
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: ""
};
}
validateForm() {
return this.state.email.length > 0 && this.state.password.length > 0;
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
}
handleSubmit = event => {
event.preventDefault();
}
render(){
return (
<div class="container">
<form onSubmit={this.handleSubmit}>
<div id="login">
<div class="form-group">
<h2 align="center">Login Form</h2>
Email :
<input type="email" id="email" value={this.state.email} onChange={this.handleChange} class="form-control" placeholder="Email Address"/><br/>
Password :
<input type="password" id="password" value={this.state.password} onChange={this.handleChange} class="form-control" placeholder="Password"/><br/>
Sign Up<br/><br/>//here I want to change
<button id="send" disabled={!this.validateForm()} class="btn btn-default">Sign In</button>
</div>
</div>
</form>
</div>
);
}
}
export default App;
I have added the Anchor tag in that but it won't work . I want to create the link in place of anchor tag in that onclick the signup page will open. I have started to create signUp page also
here is my code:
import React, { Component } from 'react';
import './App.css';
export default class Signup extends Component {
render(){
return (
<div class ="container">
<form>
<div id="signup">
<div class="form-group">
First Name :
<input type="text" id="first" class="form-control" placeholder="First Name"/><br/>
Last Name :
<input type="text" id="last" class="form-control" placeholder="Last Name"/><br/>
Email :
<input type="email" id="email" class="form-control" placeholder="Email"/><br/>
Password :
<input type="password" id="password" class="form-control" placeholder="Password"/><br/>
Re-enter Password :
<input type="password" id="confirm" class="form-control" placeholder="Confirm Password"/><br/>
<button id="save">Save</button>
</div>
</div>
</form>
</div>
);
}
}
How do I create the routes to go from one page to another?
Use Link instead of a tag:
import { Link } from 'react-router-dom';
.
.
<Link to='/signup'>Sign Up</Link>
EDIT: I'm updating the code for your solution for now, but I need you to understand you might not be getting such a solution whenever you post questions here. Stack Overflow requires you to read through any documentation and do extensive research before asking any question.
I need you to look at the code below and fully understand it by reading the React Router docs before copy-pasting it.
Change your App.js to:
import React, { Component } from 'react';
import { BrowserRouter as Router, Link, Route, Switch } from 'react-router-dom';
import Signup from './Signup';
import './App.css';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: ""
};
}
validateForm() {
return this.state.email.length > 0 && this.state.password.length > 0;
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
}
handleSubmit = event => {
event.preventDefault();
}
render() {
return (
<div class ="container">
<form onSubmit={this.handleSubmit}>
<div id="login">
<div class="form-group">
<h2 align="center">Login Form</h2>
Email :
<input type="email" id="email" value={this.state.email} onChange={this.handleChange} class="form-control" placeholder="Email Address"/><br/>
Password :
<input type="password" id="password" value={this.state.password} onChange={this.handleChange} class="form-control" placeholder="Password"/><br/>
<Link to="/signup">Signup</Link>
<button id="send" disabled={!this.validateForm()} class="btn btn-default">Sign In</button>
</div>
</div>
</form>
</div>
)
}
}
class App extends Component {
render() {
return (
<Router>
<Switch>
<Route exact path='/' component={Login}/>
<Route path='/signup' component={Signup}/>
</Switch>
</Router>
);
}
}
export default App;
and your expected working is achieved. Let me know if that solved by accepting this answer, or comment below.
P.S: React Router docs: https://reacttraining.com/react-router/web/guides/philosophy
Happy Coding!
If you are using react-router 4.x and above, then import it like this
import {Link} from 'react-router-dom'
For react-router versions < 4.x
import {Link} from 'react-router';
And in your return, you can link to another page by
<Link to="/signup">Signup</Link>

Categories