I am a beginner in react. I was working on the react function component with forms using hooks. Can anyone please tell how can I apply validation on email text when it is invalid or empty, and disable the continue button if the form is not valid.
import React, { useState } from "react";
const ForgotPassowrd = () => {
const [emailId, setemailId] = useState("");
const forgotPasswordClick = (event) => {};
return (
<div>
<div className="NewPassword-form form_wrapper">
<div className="form-body">
<form action="#">
<div>
<div className="form-group">
<label htmlFor="password">Email-Id</label>
<div className="input-group">
<input type="text" className="form-control" value={emailId} onChange={(event)=>
setemailId(event.target.value)}/>
</div>
</div>
<button type="button" onClick={forgotPasswordClick} className="btn btn-lg
btn-block">Continue</button>
</div>
</form>
</div>
</div>
</div>
);
};
export default ForgotPassowrd;
**Try it.This may be helpfull for you! If you can any queries comment below.**
const LoginV2 = ({}) => {
// state
const [loginForm, setLoginForm] = useState({
email: undefined,
password: undefined,
emailValid: false,
passwordValid: false,
});
const [error, setError] = useState({ email: undefined, password: undefined });
// state update
const handleLoginForm = (e) => {
checkValidity(e.target.name, e.target.value);
setLoginForm({ ...loginForm, [e.target.name]: e.target.value });
};
// validation function
const checkValidity = (inputName, inputValue) => {
switch (inputName) {
case "email":
let pattern = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
loginForm.emailValid = pattern.test(inputValue);
break;
case "password":
loginForm.passwordValid = inputValue.length >= 6;
break;
default:
break;
}
};
// form submit
const onSubmitLoginForm = () => {
console.log(loginForm);
if (!loginForm.emailValid) {
setError(prevError => {
return {
...prevError,
email: "Invalid Email Address"
}
});
}
if (!loginForm.passwordValid) {
setError(prevError => {
return {
...prevError,
password: "Password must be at least six characters long"
}
});
}
return (
<div class="row">
<div class="form">
<div class="col span-1-of-2">
<div class="username">
<p class="login-para text-align-center">LOG IN VIA EMAIL</p>
<form method="post" action="#" class="login-form">
{error.email && (
<div class="alert alert-danger">
<p>
{" "}
<strong> {alertText} </strong> {error.email}
</p>
</div>
)}
{error.password && (
<div class="alert alert-danger">
<p>
{" "}
<strong> {alertText} </strong> {error.password}
</p>
</div>
)}
<div class="info-box">
{icon && <i class="fas fa-user-alt login-icon"></i>}
<input
type="text"
name="email"
placeholder="Your Email"
onChangeText={(e) => handleLoginForm(e)}
inputValue={loginForm.email}
/>
</div>
<div class="info-box">
{icon && <i class="fas fa-user-alt login-icon"></i>}
<input
type="password"
name="password"
placeholder="Your Password"
onChangeText={(e) => handleLoginForm(e)}
inputValue={loginForm.password}
/>
</div>
<div class="buttons">
<input type="checkbox" />
<label class="remember" for="#">
Remember me
</label>
<div class="form-btn-disabled" onClick={onSubmitLoginForm}
>
LOGIN NOW
</div>
</div>
</form>
</div>
</div>
</div>
</div>
);
};
export default LoginV2;
Try below. I have added inline comments for better understanding. Comment your queries if you have any.
// Regex to check valid email
const validEmail = /^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$/g
import React, { useState } from "react";
const ForgotPassowrd = () => {
const [emailId, setemailId] = useState("");
//State to disable/enable continue button
const [disableBtn, setDisableBtn] = useState(false);
const forgotPasswordClick = (event) => {};
const handleSubmit = e => {
e.preventDefault();
// Do whatever you want to do after you click submit button
}
const handleChange = e => {
setemailId(event.target.value);
setDisableBtn(validEmail.test(e.target.value));
}
return (
<div>
<div className="NewPassword-form form_wrapper">
<div className="form-body">
{/* Remove action and use onSubmit handler*/}
<form onSubmit={handleSubmit}>
<div>
<div className="form-group">
<label htmlFor="password">Email-Id</label>
<div className="input-group">
{/* Introduced name attribute to help you with handleSubmit handler*/}
<input name="email" type="text" className="form-control" value={emailId} onChange={(event)=>
setemailId(event.target.value)}/>
</div>
</div>
<button onClick={forgotPasswordClick} className="btn btn-lg
btn-block" disabled={disableBtn}>Continue</button>
</div>
</form>
</div>
</div>
</div>
);
};
export default ForgotPassowrd;
Related
Hello guys i have a react project made with react, node, express, and mysql. The thing is i want to get email from login and pass to home page. How do i do that, i dont want to use useParams() because the user can input their email in the link, i want to avoid that. Is there any way to do that and if you can, can you give code example.
Login
const Login = () => {
let navigate = useNavigate();
const [emailLog, setEmailLog] = useState("");
const [passwordLog, setPasswordLog] = useState("");
const [loginStatus, setLoginStatus] = useState("");
Axios.defaults.withCredentials = true;
const login = (e) => {
e.preventDefault()
Axios.post("http://localhost:3001/login" , {
email: emailLog,
password: passwordLog
}).then((response)=> {
console.log(response)
if(response.data.message) {
alert((response.data.message))
} else{
setLoginStatus(response.data[0].email)
alert("Redirecting")
navigate("/home")
}
})
}
useEffect(() => {
Axios.get('http://localhost:3001/login').then((response)=> {
if(response.data.loggedIn == true) {
setLoginStatus(response.data.email[0].email)
}
})
})
return (
<div>
<img className="wave" src={Wave} />
<img className="wave2" src={WaveV2} />
<div className="wrapper">
<div className="img">
{/* <img src={Background}/> */}
</div>
<div className="register-content">
<div className='registerForm'>
<img src={Avatar} />
<h2 className="title">Welcome</h2>
<div className="input-div one">
<div className="i">
<i className="fas fa-user"><GrMail /></i>
</div>
<div className="div">
<input type="email" className="input" placeholder='Email' required
onChange={(e)=> {
setEmailLog(e.target.value)
}}/>
</div>
</div>
<div className="input-div pass">
<div className="i">
<i className="fas fa-lock"><AiFillLock /></i>
</div>
<div className="div">
<input type="password" className="input" placeholder='Password' required
onChange={(e)=> {
setPasswordLog(e.target.value)
}}/>
</div>
</div>
Don't have an account ?
<button type='submit' className='btn' onClick={login} data={emailLog}>Login</button>
</div>
</div>
</div>
</div>
)
}
export default Login
App.js
function App() {
const [invoice, setInvoice] = useState("");
const [date, setDate] = useState ("");
const [currency, setCurrency] = useState ("IDR");
const [ myFile, setMyFile] = useState("");
const [test, setTest] = useState("anjay#anjay.com");
Axios.defaults.withCredentials = true;
return (
<div className="App">
<BasicExample />
<div className='formInput'>
<form method='POST' encType='multipart/form-data' action='http://localhost:3001/upload'>
<div className='textUser'>
<h1>{props.data}</h1>
</div>
<input className='inputForm' defaultValue={test} type="email" disabled name='email' />
<input className='inputForm' type="number" placeholder='Invoice No' name='InvoiceNo' />
<input className='inputForm' type="date" name='Invoice_Date' />
<input className='inputForm' type="text" placeholder='Description' name='Description' />
<select className='selectBox' name='Currency' onChange={(e)=> {
setCurrency(e.target.value);
}}>
<option value="IDR">IDR</option>
<option value="USD">USD</option>
<option value="YEN">YEN</option>
</select>
<input className='inputForm' type="number" placeholder='Amount' name='Amount'/>
<input className='custom-file-upload' multiple type="file" name="DocumentFile" onChange={(e)=> {
setMyFile(e.target.value);
}} />
<button className='btnSubmit'>Submit</button>
</form>
</div>
</div>
);
}
export default App;
I think props drilling should solve it.
example
Login Component
function Login({email, setEmail}){
// you need to update state email here
}
Home or App.js
function App(){
const [email, setEmail] = useState("");
// here you should pass the props to login component,
// so you have the ability to set or asign the email state
<Login email={email} setEmail={setEmail} />
}
If you want to send data tp one page, you can use state with navigate.
navigate("/home", {state: { email: emailLog }})
you can get data from your home component like,
{props.location.state.email}
I have the following code in my react app and I need to have empty input areas after submitting. Please assist me.
import { useRef } from 'react';
import './Contact.css';
import emailjs from 'emailjs-com'
import { useState, useEffect } from 'react';
const Contact = () => {
const formRef = useRef();
const [done, setDone] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
emailjs.sendForm(
'service_py6v3mm',
'template_db5q8nx',
formRef.current,
'mJDC1if10C25Z-TZC'
)
.then((result) => {
console.log(result.text);
setDone(true);
}, (error) => {
console.log(error.text);
});
}
return (
<div className="c">
<div className='c-wrapper'>
<div className='c-left'>
<h1 className='c-title'> Let's discuss!</h1>
<div className='c-info'>
<div className='c-info-item'>
<div className="c-info-item">
<img
src="./images/Phone.jpg"
alt=""
className="c-icon"
/>
+12345678 </div>
<div className="c-info-item">
<img className='c-icon'
src="./images/Email.png" alt='Email' />
messimacky#gmail.com
</div>
<div className="c-info-item">
<img className='c-icon'
src="./images/Location.jpeg"
alt=" " />
Addis Ababa, Wolo Sefer, Ethio-China Road, Ethiopia
</div>
</div>
</div>
</div>
<div className='c-right'>
<p className='c-desc'> <b> Get in touch!</b>
</p>
<form ref={formRef} onSubmit={handleSubmit}>
<input type='text' placeholder='Name' name='username' />
<input type='text' placeholder='Subject' name='user_subject' />
<input type='text' placeholder='Your email here... ' name='user_email' />
<textarea rows={5} placeholder='message' name='message' /> <br />
<button>Submit</button>
{done && <p> Thank you I will contact you soon!</p>}
</form>
</div>
</div>
</div>
)
}
export default Contact
You can bind every input value to a state and empty them when you submit it. Here I add an example for the username. You can multiply it and use it.
const [username, setUsername] = useState('Name');
const submitFunctionWhichDeletes = () => {
console.log(username);
setUsername('');
}
<input ... value={username} onChange={e => setUsername(e.target.value)} ... />
const compForm = ()=>{
const [formData,addFormData] = useState({
username:"",
subject:"",
email:"",
message:""
})
cosnt formSubmit =()=>{
// make api call
addFormData({
username:"",
subject:"",
email:"",
message:""
})
}
const formData = (e,filed)=>{
const temp = {...formData}
if (filed === "username"){
temp.username = e.target.value
}
else if(filed === "subject"){
temp.subject = e.target.value
}
else if(filed === "email"){
temp.email = e.target.value
}
else if(filed === "message"){
temp.message = e.target.value
}
addFormData(temp)
}
return(
<>
<input type='text' placeholder='Name' name='username'
value={formData.username} onChange={(e)=>formData(e,username)}/>
<input type='text' placeholder='Subject' name='user_subject'
value={formData.subject} onChange={(e)=>formData(e,subject)}/>
<input type='text' placeholder='Your email here... ' name='user_email'
value={formData.email} onChange={(e)=>formData(e,email)}/>
<textarea rows={5} placeholder='message' name='message'
value={formData.message} onChange={(e)=>formData(e,message)}/>
<button onClick = {(e)=>formSubmit()}>Submit</button>
<>
)
}
I have a Login component and I receive that error: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak. I googled for the error and found some people having the same issue and I tried to solve it like them, but it didn't work for me. Why I have this error, and how do I fix it? Thanks
COMPONENT LOGIN
import React, { useState, useContext, useEffect } from "react";
import { useLocation } from "wouter";
import logic from "../../logic";
import { AuthContext } from "../../context/AuthContext";
import validate from "./validateRulesLogin";
import literals from "../../common/i18n/literals";
import "./index.css";
export default function Login(language) {
const [, setAuth] = useContext(AuthContext);
const [, pushLocation] = useLocation();
const [messageError, setMessageError] = useState("");
const [errorsValidateForm, setErrorsValidateForm] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const [data, setData] = useState({ email: "", password: "" });
const { lang } = language;
const { login_notRegister } = literals;
useEffect(() => {}, [errorsValidateForm, isSubmitting]);
let isCancelled = false;
async function handleOnSubmit(e) {
e.preventDefault();
if (!isSubmitting) {
let errorsForm = validate(data, lang);
if (Object.keys(errorsForm).length === 0 && !isCancelled) {
setIsSubmitting(true);
const { email, password } = data;
try {
await logic.loginUser(email, password, lang);
setAuth(true);
setIsSubmitting(false);
pushLocation("/");
} catch (error) {
setMessageError(error.message);
setIsSubmitting(false);
setTimeout(() => {
setMessageError("");
}, 3000);
}
}
setErrorsValidateForm(errorsForm);
}
return () => {
isCancelled = true;
};
}
const handleOnChangeData = (e) => {
e.preventDefault();
setData({
...data,
[e.target.name]: e.target.value,
});
};
return (
<>
{messageError && (
<div className="message">
<p className="messageError">{messageError}</p>
</div>
)}
<section className="hero is-fullwidth">
<div className="hero-body">
<div className="container">
<div className="columns is-centered">
<div className="column is-4">
<form id="form" onSubmit={(e) => handleOnSubmit(e)} noValidate>
<div className="field">
<p className="control has-icons-left">
<input
className="input"
name="email"
type="email"
placeholder="Email"
onChange={handleOnChangeData}
required
/>
<span className="icon is-small is-left">
<i className="fas fa-envelope"></i>
</span>
</p>
{errorsValidateForm.email && (
<p className="help is-danger">
{errorsValidateForm.email}
</p>
)}
</div>
<div className="field">
<p className="control has-icons-left">
<input
className="input"
name="password"
type="password"
placeholder="Password"
onChange={handleOnChangeData}
required
/>
<span className="icon is-small is-left">
<i className="fas fa-lock"></i>
</span>
</p>
{errorsValidateForm.password && (
<p className="help is-danger">
{errorsValidateForm.password}
</p>
)}
</div>
<div className="field">
<p className="control">
<button type="submit" className="button is-success">
Login
</button>
</p>
</div>
<div>
{login_notRegister[lang]}
</div>
</form>
</div>
</div>
</div>
</div>
</section>
</>
);
}
I have a form with several fields. And I am doing the validation as well.
So on the onSubmit it calls to a function handleSubmit and there I am doing the validation.
So if there are any empty fields, they will produce an error and will be shown below each field.
If there are NO errors, it will be route to the /register-success component.
Now my problem is, if there are any empty fields when I click on Register button, those respective errors are being set using setErrors. But it is not being updated to the errors variable right after it is being set.
So unlike in class components I could have used a callback function with setState but in hooks I saw a workaround to use useEffect. It is working, but now I don't know how to redirect the page to /register-success within the useEffect because I can't do it within the handleSubmit because of the errors are not getting updated even after the setErrors
So How can I do the callback operation using react hooks or how can I redirect the page within the useEffect?
Here's my code:
import React, { useState, useEffect } from "react";
import { Link, useHistory } from "react-router-dom";
function Register() {
const [values, setValues] = useState({});
const [errors, setErrors] = useState({});
const handleChange = (event) => {
event.persist();
setValues((values) => ({
...values,
[event.target.name]: event.target.value,
}));
};
useEffect(() => {
if (Object.keys(errors).length === 0) {
// RIDERECT TO THE /register-success ==============================
} else {
// alert("Errors found");
}
}, [errors]);
const validateForm = (values) => {
let allErrors = {};
if (!values.name) {
allErrors.name = "User name is required!";
}
if (!values.phonenumber) {
allErrors.phonenumber = "Phone number is required!";
}
if (!values.email) {
allErrors.email = "Email address is required!";
} else if (!/\S+#\S+\.\S+/.test(values.email)) {
allErrors.email = "Email address is invalid!";
}
if (!values.password) {
allErrors.password = "Please provide the password!";
}
if (!values.confirmpassword) {
allErrors.confirmpassword = "Please confirm the password is the same!";
}
return allErrors;
};
const handleSubmit = (event) => {
if (event) event.preventDefault();
setErrors(validateForm(values));
};
return (
<form onSubmit={handleSubmit}>
<div className="container login-container">
<div className="row">
<div className="col-md-6 login-form-2">
<h3>Register to post your ad</h3>
<div className="form-group">
<input
onChange={handleChange}
type="text"
className="form-control"
placeholder="Name *"
name="name"
value={values.name || ""}
/>
{errors.name && (
<div class="alert alert-danger" role="alert">
{errors.name}
</div>
)}
</div>
<div className="form-group">
<input
onChange={handleChange}
type="text"
name="phonenumber"
className="form-control"
placeholder="Phone Number *"
value={values.phonenumber || ""}
/>
{errors.phonenumber && (
<div class="alert alert-danger" role="alert">
{errors.phonenumber}
</div>
)}
</div>
<div className="form-group">
<input
onChange={handleChange}
type="text"
name="email"
className="form-control"
placeholder="Your Email *"
value={values.email || ""}
/>
{errors.email && (
<div class="alert alert-danger" role="alert">
{errors.email}
</div>
)}
</div>
<div className="form-group">
<input
onChange={handleChange}
type="password"
name="password"
className="form-control"
placeholder="Password *"
value={values.password || ""}
/>
{errors.password && (
<div class="alert alert-danger" role="alert">
{errors.password}
</div>
)}
</div>
<div className="form-group">
<input
onChange={handleChange}
type="password"
className="form-control"
placeholder="Confirm Password *"
name="confirmpassword"
value={values.confirmpassword || ""}
/>
{errors.confirmpassword && (
<div class="alert alert-danger" role="alert">
{errors.confirmpassword}
</div>
)}
</div>
<div className="form-group">
{/* <Link to="/register-success"> */}
<input type="submit" className="btnSubmit" value="Register" />
{/* </Link> */}
</div>
<div className="form-group btnForgetPwd">
By clicking "Register" you are agreeing to our{" "}
<Link target="_blank" to="/terms-and-conditions">
<a
style={{
color: "white",
textDecoration: "underline",
fontStyle: "italic",
}}
>
Terms and Conditions
</a>
</Link>
</div>
</div>
<div className="col-md-6 login-form-1">
<div className="login-logo">
<img src="https://image.ibb.co/n7oTvU/logo_white.png" alt="" />
</div>
{/* Register */}
<h3>Already a member? Login</h3>
<div className="form-group text-center pt-5">
<Link to="/login">
<input type="button" className="btnSubmit" value="Login" />
</Link>
</div>
</div>
</div>
</div>
</form>
);
}
export default Register;
You can do something like that :
const handleSubmit = (event) => {
if (event) event.preventDefault();
const validationErrors = validateForm(values)
if(Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
return;
}
// REDIRECT TO THE /register-success ==============================
};
If you've got errors redirection won't be triggered and component will re-render with errors updated
So I have a project I did before in Vue and now am doing in React(w/ hooks) in order to learn it. I'm having a few problems and concerns that I'm not going about it the right way(certain I'm not).
One of the biggest problems I'm having is where the state is updated via onchange and onblur. Many times the state values would be one "tick" behind. I found that with old class components you could use a callback within setState.
I'm trying to make instant form validation feedback show/hide as the user updates the fields.
With hooks, it is supposed to be done with useEffect. I have it "working" right now but it seems it's rendering more times than it should. I can tell by the fact it runs the checkValues() twice to show the current state values .
An example of the nature of my misunderstanding is if I don't put setinValid(validateForm()); within the onchange AND the useEffect.. it won't update the state for inValid which disables/enables the submit button. This seems redundant to me and I'm not sure why it "works" as is.
Any help/insight on how to properly do what I'm attempting would be greatly appreciated.
https://codesandbox.io/s/user-listing-in-react-9ip4t?fontsize=14&module=%2Fsrc%2Fcomponents%2FUser%2FUserAdd.js
import React from "react";
import { Link } from "react-router-dom";
// import { saveUserToLocalStorage } from "../../utils/StorageHelper";
// import { User } from "../../utils/UserClass";
const UserAdd = props => {
const [userName, setuserName] = React.useState("");
const [userAge, setuserAge] = React.useState("");
const [userEmail, setuserEmail] = React.useState("");
const [inValid, setinValid] = React.useState(true);
const [errors, setErrors] = React.useState({
name: [],
age: [],
email: []
});
React.useEffect(() => {
checkValues();
setinValid(validateForm());
}, [userName, userAge, userEmail, inValid]);
const validateForm = () => {
if (isNaN(userAge)) {
return true;
}
if (!userName || !userAge || !userEmail) {
return true;
}
if (!validateEmail(userEmail)) {
return true;
}
return false;
};
function checkIndividualErrors() {
if (userName.length === 0) {
setErrors({ ...errors, name: ["User name is required"] });
} else {
setErrors({ ...errors, name: [] });
}
}
const checkValues = () => {
console.log(
"username:",
userName,
"age:",
userAge,
"useremail: ",
userEmail,
"invalid:",
inValid
);
};
const validateEmail = mail => {
if (/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(mail)) {
return true;
}
return false;
};
return (
<div>
<h2 class="line-container">
<span>Add a new User</span>
</h2>
<hr />
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">Name</label>
</div>
<div class="field-body">
<div class="field">
<p class="control">
<input
class="input"
type="text"
name="name"
placeholder="Name"
value={userName}
onChange={e => {
setuserName(e.target.value);
setinValid(validateForm());
checkIndividualErrors();
}}
onBlur={checkIndividualErrors}
/>
<span class="error">{errors.name}</span>
</p>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">Age</label>
</div>
<div class="field-body">
<div class="field">
<p class="control">
<input
class="input"
type="text"
name="age"
placeholder="Age"
value={userAge}
onChange={e => {
setuserAge(e.target.value);
setinValid(validateForm());
// checkIndividualErrors not fully implemented yet
}}
/>
<span class="error" />
</p>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">Email</label>
</div>
<div class="field-body">
<div class="field">
<p class="control">
<input
class="input"
type="email"
name="email"
placeholder="Email"
value={userEmail}
onChange={e => {
setuserEmail(e.target.value);
setinValid(validateForm());
// checkIndividualErrors not fully implemented yet
}}
/>
<span class="error" />
</p>
</div>
</div>
</div>
<p class="" style={{ margin: "0 auto" }}>
<button
disabled={inValid}
class="button is-primary"
style={{ marginRight: "10px" }}
>
Create
</button>
<Link to="/" class="button">
Cancel
</Link>
<Link to="/" class="goBack">
<span style={{ fontSize: "20px" }}>←</span>
</Link>
</p>
</div>
);
};
export default UserAdd;