How to validate email and password using react hooks? - reactjs

I am getting state values while clicking submit button but I am unable to do the validation for my login form and how to display the error messages below the input field when I enter my input wrong or empty. please give me a solution to this.Thanks in advance.
const Login = () => {
const [state, setState] = useState({
email: "",
password: ""
});
const handleChange = (e) => {
const {id, value} = e.target
setState(prevState => ({
...prevState,
[id]: value
}))
}
const handleSubmitClick = (e) => {
e.preventDefault();
console.log("Authenticated",state);
}
return(
<>
<div className="container">
<div className="title">
<form onSubmit={handleSubmitClick}>
<div className="form-group">
<input
type="email"
className="email"
placeholder="Email"
value={state.email}
onChange={handleChange}/>
</div>
<div className="form-group">
<input
type="password"
className="password"
placeholder="Password"
value={state.password}
onChange={handleChange}/>
</div>
<button type="submit" className="button">Enter</button>
</form>
</div>
</div>
</>
)
}
export default Login;

If you want to perform client-side validation, you can create hook like this:
const useEmailValidation = (email) => {
const isEmailValid = /#/.test(email); // use any validator you want
return isEmailValid;
};
And then you can use this hook in your form component:
...
const isEmailValid = useEmailValidation(state.email);
const isPasswordValid = usePasswordValidation(state.password);
const isFormValid = isEmailValid && isPasswordValid;
return (
...
<input
className={classNames({ 'invalid': !isEmailValid })}
type="email"
value={state.email}
onChange={handleChange}
/>
{!isEmailValid && 'Some error message'}
<button type="submit" disabled={!isFormValid} className="button">Enter</button>
...
);
...
Your validator hook can return validation message instead of boolean, like:
const useEmailValidation = (email) => {
if (!email || email.length === 0) {
return 'Email cannot be empty';
}
const isEmailValid = /#/.test(email); // use any validator you want
if (!isEmailValid) {
return 'Invalid email provided';
}
return null;
};
Also it is a good practice to show validation message only after field was focused before and after user tried to submit the form.

Formik is a great plugin that will help you perform form validation. The examples are also quite clear.
Or you could do something like this:
const Login = () => {
const [error, setError] = useState(null);
const [state, setState] = useState({
email: '',
password: '',
});
const validateEmail = (email) => {
const re =
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
};
const handleChange = (e) => {
const { id, value } = e.target;
setState((prevState) => ({
...prevState,
[id]: value,
}));
};
const handleSubmitClick = (e) => {
e.preventDefault();
if (!validateEmail(state.email)) {
setError('Invalid Email');
}
if (state.password.length < 8) {
setError('Password must be at least 8 chars long');
}
if (!error) {
// No errors.
}
};
return (
<>
<div className='container'>
<div className='title'>
{error && <div style={{ color: 'red' }}>{error}</div>}
<form onSubmit={handleSubmitClick}>
<div className='form-group'>
<input
type='email'
className='email'
placeholder='Email'
value={state.email}
onChange={handleChange}
/>
</div>
<div className='form-group'>
<input
type='password'
className='password'
placeholder='Password'
value={state.password}
onChange={handleChange}
/>
</div>
<button type='submit' className='button'>
Enter
</button>
</form>
</div>
</div>
</>
);
};
export default Login;

For an empty validation you can check it preventing the submit if the field is empty, like
const handleSubmitClick = (e) => {
e.preventDefault();
if(email.trim() === '' || password.trim() === ''){
//Add a h1 or section with the error message
}else{
console.log("Authenticated",state);
}
}
As long as the email field type is equal to email, which is your case, the browser should give an alert if the string is not an email. ("user#example.com")

Related

Localstorage in reactjs when it get reloaded key is present values are missing

import { useState } from "react";
function App() {
const initialValues = { username:"", password: "" };
const [formValues, setFormValues] = useState(initialValues);
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(
JSON.parse(localStorage.getItem("data")) ? true : false
);
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
setFormErrors(validate(formValues));
setIsSubmit(true);
};
const validate = (values) => {
const errors = {};
if (!values.username) {
errors.username = "Username is required!";
}
if (!values.password) {
errors.password = "Password is required";
} else if (values.password.length < 4) {
errors.password = "Password must be more than 4 characters";
} else if (values.password.length > 8) {
errors.password = "Password cannot exceed more than 10 characters";
}
return errors;
};
const logout = () => {
setIsSubmit(false);
localStorage.clear();
};
return (
<div className="container">
{Object.keys(formErrors).length === 0 && isSubmit ? (
<>
{localStorage.setItem("data", JSON.stringify(formValues))}
<div>
hello {JSON.parse(localStorage.getItem("data")).username} ,Signed
in successfully
</div>
<button onClick={logout}>LOG OUT</button>
</>
) : (
<form onSubmit={handleSubmit}>
<div>
<div>
<label>Username</label>
<input
type="text"
name="username"
placeholder="Username"
value={formValues.username}
onChange={handleChange}
/>
</div>
<p>{formErrors.username}</p>
<div>
<label>Password</label>
<input
type="password"
name="password"
placeholder="Password"
value={formValues.password}
onChange={handleChange}
/>
</div>
<p>{formErrors.password}</p>
<button>Submit</button>
</div>
</form>
)}
</div>
);
}
export default App;
once data stored in storage
when it get reloaded keys are present but value missing
when form is getting reloaded the data which is stored in the from of object in localStorage the values are getting missed while key are present.when form is getting reloaded the data which is stored in the from of object in local Storage the values are getting missed while key are present.
You need to set the handleSubmit func instead of returning the data to the local storage, as you can see in the code below.
const handleSubmit = (e) => {
e.preventDefault();
setFormErrors(validate(formValues));
setIsSubmit(true);
localStorage.setItem("data", JSON.stringify(formValues));
};
Remove this line {localStorage.setItem("data", JSON.stringify(formValues))} in return method.

How to put Regex different input Validation in React

I am trying to put regex input validation in my react project, but getting continuous error i.e Validation is not there and Validation(values) is not there.
TeacherRegistration.js
import React, { useState } from 'react'
import Validation from '../Validation'
const TeacherRegistraion = () => {
const [teacherRegistraion, setTeacherRegistration] = useState({
tFirstName: '',
tLastName: '',
tEmail: '',
})
const [error, setError] = useState({});
const handleInput = (e) => {
const name = e.target.name;
const value = e.target.value;
console.log(name, value);
setTeacherRegistration({ ...teacherRegistraion, [name]: value });
}
const handleSubmit = (e) => {
e.preventDefault();
setError(Validation(values));
const newRecord = { ...teacherRegistraion, id: new Date().getTime().toString() }
console.log(newRecord)
setTeacherRegistration(
{
tFirstName: '',
tLastName: '',
tEmail: '',
}
)
}
return (
<div className='container'>
<div className='title'> Registration</div>
<div className="content">
<form action="" onSubmit={handleSubmit}>
<div className="user-details">
<div className='input-box'>
<span htmlFor="tFirstName">First Name</span>
<input type="text"
name='tFirstName'
value={teacherRegistraion.tFirstName}
onChange={handleInput}
id='tFirstName'
required
/>
{error.tFirstName && <p className='error'>{error.tFirstName}</p>}
</div>
<div className='input-box'>
<span htmlFor="tLastName">Last Name</span>
<input type="text"
name='tLastName'
value={teacherRegistraion.tLastName}
onChange={handleInput}
id='tLastName'
required
/>
{error.tLastName && <p className='error'>{error.tLastName}</p>}
</div>
<div className='input-box'>
<span htmlFor="tEmail">Email</span>
<input type="email"
name='tEmail'
value={teacherRegistraion.tEmail}
onChange={handleInput}
id='tEmail'
required
/>
{error.tEmail && <p className='error'>{error.tEmail}</p>}
</form>
</div>
</div>
)
I am trying to put regex input validation in my react project, but getting continuous error i.e Validation is not there and Validation(values) is not there.
Validation.js
const Validation = (values) => {
let errors = {};
if (!values.tFirstName) {
errors.tFirstName = 'Firstname is required'
}
if (!values.tLasttName) {
errors.tLasttName = 'Lasttname is required'
}
if (!values.tEmail) {
errors.email = 'Email is required'
}
else if (!/\S+#\S+\. \S+/.test(values.tEmail)) {
errors.tEmail = 'Email is invalid'
}
return errors;
}
export default Validation;
I am trying to put regex input validation in my react project, but getting continuous error i.e Validation is not there and Validation(values) is not there.

Dealing with multiple boolean state variables for validation

I'm building a form in React, and have a function to validate the email and password as provided by the user: if either do not pass validation, a state variable is flipped from true to false, and an error message is conditionally rendered:
State variables
const [isEmail, setEmail] = useState(true);
const [isPassword, setPassword] = useState(true);
Validation function
const validateEmailAndPassword = (email, password) => {
const emailRegEx =
/^(([^<>()\[\]\\.,;:\s#"]****************;
email.match(emailRegEx) ? setEmail(true) : setEmail(false);
password.length > 8 ? setPassword(true) : setPassword(false);
};
Error message
<p className="errors">{!isEmail ? errors.email : null}</p>
Instead of declaring each state variable individually, what would be the best way to declare them toegther, as I've done with the other inputs in my form?
Here's the complete file:
import { useState, useEffect } from "react";
const Form = () => {
const [{ email, password,colour }, setFormDetails] = useState({
email: "",
password: "",
colour: ""
});
const [isEmail, setEmail] = useState(true);
const [isPassword, setPassword] = useState(true);
const [isTigerChecked, setTigerChecked] = useState(false);
useEffect(() => {
document.title = 'Contact form'
},[])
const errors = {
password: "Password needs to contain 8 or more characters",
email: "Please enter a valid email",
};
const handleChange = (e) => {
e.preventDefault();
const { name, value } = e.target;
setFormDetails((prevForm) => ({
...prevForm,
[name]: value,
}));
};
const validateEmailAndPassword = (email, password) => {
const emailRegEx =
/^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
email.match(emailRegEx) ? setEmail(true) : setEmail(false);
password.length > 8 ? setPassword(true) : setPassword(false);
};
const handleClick = (e) => {
e.target.checked ? setTigerChecked(true) : setTigerChecked(false)
}
const handleSubmit = (e) => {
e.preventDefault();
validateEmailAndPassword(email, password);
};
return (
<div className="form-container">
<p>Contact form</p>
<form onSubmit={handleSubmit}>
<input
className="form-element"
type="text"
placeholder="Enter email address"
name="email"
onChange={handleChange}
/>
<p className="errors">{!isEmail ? errors.email : null}</p>
<input
className="form-element"
type="password"
placeholder="Enter password"
name="password"
onChange={handleChange}
/>
<p className="errors">{!isPassword ? errors.password : null}</p>
<fieldset className="form-element">
<legend>Please select a colour</legend>
<select name="colour" id="colour" onChange = {handleChange}>
<option value="Blue">Blue</option>
<option value="Green">Green</option>
<option value="Red">Red</option>
<option value="Black">Black</option>
<option value="Brown">Brown</option>
</select>
</fieldset>
<fieldset className="form-element">
<legend>Please select your animals</legend>
<div className="checkbox">
<input type="checkbox" id="bear" name="bear" />
<label for="bear"> Bear</label>
<br></br>
<input
type="checkbox"
id="Tiger"
name="Tiger"
onClick={handleClick}
/>
<label for="Tiger"> Tiger</label>
<br></br>
<input type="checkbox" id="Snake" name="Snake" />
<label for="Snake"> Snake</label>
<br></br>
<input type="checkbox" id="Donkey" name="Donkey" />
<label for="Donkey"> Donkey</label>
<br></br>
</div>
</fieldset>
{isTigerChecked ? (
<textarea
id="tiger-type"
name="tiger-type"
rows="4"
cols="50"
placeholder="Please enter type of Tiger"
/>
) : null}
<button type="submit">Submit</button>
</form>
</div>
);
};
export default Form;
I would do this:
Get rid of the isEmail and isPassword states, and make an errors state with an empty object as the initial value.
const [errors, setErrors] = useState({});
and change the name of the errors obj that holds the error messages to errorMessages
const errorMessages = {
password: "Password needs to contain 8 or more characters",
email: "Please enter a valid email",
}
Within your validate function, make an errorsObj variable assigned to an empty object. If email doesn't match, update the errorsObj so that the email key is assigned to the email error string from your errors object (same for password).
const errorsObj = {};
if(!email.match(emailRegEx)) errorsObj['email'] = errors['email']
if (!(password.length > 8)) errorsObj['password'] = errors['password']
setErrors(errorsObj);
now when conditionally rendering the error messages, do this
{!!errors['email'] && <p className="errors">{errors['email'}</p>}
{!!errors['password'] && <p className="errors">{errors['password'}</p>}
you could also adjust your handleChange function to update errors properly
const handleChange = (e) => {
e.preventDefault();
const { name, value } = e.target;
setFormDetails((prevForm) => ({
...prevForm,
[name]: value,
}));
if (errors[name]) {
setErrors(prevState => {
delete prevState[name];
return prevState;
}
}
};

How to add email validation to below code?

The below code is using cards to show account creation, deposit and other module.
I need to refractor the code to add email, name, and password field validation, but I am not able to do it.
context.js
const Route = ReactRouterDOM.Route;
const Link = ReactRouterDOM.Link;
const HashRouter = ReactRouterDOM.HashRouter;
const UserContext = React.createContext(null);
function Card(props){
function classes(){
const bg = props.bgcolor ? ' bg-' + props.bgcolor : ' ';
const txt = props.txtcolor ? ' text-' + props.txtcolor: ' text-white';
return 'card mb-3 ' + bg + txt;
}
return (
<div className={classes()} style={{maxWidth: "18rem"}}>
<div className="card-header">{props.header}</div>
<div className="card-body">
{props.title && (<h5 className="card-title">{props.title}</h5>)}
{props.text && (<p className="card-text">{props.text}</p>)}
{props.body}
{props.status && (<div id='createStatus'>{props.status}</div>)}
</div>
</div>
);
}
function CardForm(props) {
const ctx = React.useContext(UserContext);
return (
<>
<div style={{maxWidth: "18rem"}}>
<div className="name-field" style={{display: props.showName}}>
Name<br/>
<input type="input"
id="txtName"
className="form-control"
placeholder="Enter name"
onChange={e => ctx.name=e.currentTarget.value} /><br/>
</div>
<div className="email-field" style={{display: props.showEmail}}>
Email address<br/>
<input type="input"
id="txtEmail"
className="form-control"
placeholder="Enter email"
onChange={e => ctx.email=e.currentTarget.value}/><br/>
</div>
<div className="password-field" style={{display: props.showPassword}}>
Password<br/>
<input type="password"
id="txtPassword"
className="form-control"
placeholder="Enter password"
onChange={e => ctx.password=e.currentTarget.value}/><br/>
</div>
<div className="amount-field" style={{display: props.showAmount}}>
Amount<br/>
<input type="number"
className="form-control"
placeholder="Enter amount"
onChange={e => ctx.balance=e.currentTarget.value}/><br/>
</div>
</div>
</>
)
}
creatAccount.js
function CreateAccount(props){
const [show, setShow] = React.useState(true);
const [status, setStatus] = React.useState('');
const ctx = React.useContext(UserContext);
function addUser() {
ctx.balance = '0';
fetch(`/account/find/${ctx.email}`)
.then(response => response.json())
.then(data => {
console.log(data);
if (data.length===0) ctx.user = true;
})
.then(() => {
if (ctx.user===true) {
const url = `/account/create/${ctx.name}/${ctx.email}/${ctx.password}/${ctx.balance}`;
(async () => {
var res = await fetch(url);
var data = await res.json();
console.log(data);
})();
ctx.user='';
setShow(false);
} else {
ctx.user='';
setStatus('User already exists with that email');
setTimeout(() => setStatus(''),3000);
}})
}
return (
<Card
bgcolor="primary"
header="Create Account"
text=""
status={status}
body={
<>
{show ?
<>
<CardForm setShow={setShow} showAmount="none"/>
{<button type="submit" className="btn btn-light" onClick={addUser}>Create Account</button>}
</>
:
<Success setShow={setShow}/>}
</>
}
/>
);
}
function Success(props) {
return (
<>
<h5>Success!</h5><br/>
<button type="submit"
className="btn btn-light"
onClick={() => props.setShow(true)}>Add another account</button>
</>
)
}
I have tried multiple solutions from online content, but they do not solve the problem.
Lets simplify this
Using NPM package email-validator
Install via NPM
npm install email-validator
import * as EmailValidator from 'email-validator';
Bind your local state to your input field e.g
const [email, setEmail] = useState("");
const [valid, setIsValid] = useState(false);
<input
type="text"
name="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
Create a function to check for email validation like below
const validateEmail = (email) => {
setIsValid(EmailValidator.validate(email));
};
Now there comes two cases. One is to show the validation on change the input field or check on submitting the whole form. To give the validation message while inputting email, you have to use the useEffect hook just like below
useEffect(() => {
if (email) {
validateEmail(email);
}
}, [email, validateEmail]);
You can use the valid state for validation message while user is entering the email something like below
<span>{valid ? 'Email format valid' : 'Invalid email format'} <span>
Second Case
just call the function we created above for email validation and check the valid state.

How to write validations for email and password using react hooks

I am working on React in that project I am trying to write validations for Email and password by
using react hooks But I don't know how to start it write it so please help to achieve this.
What I want exactly is I hard coded Email and Password in my code. Now Just I want to write validations for Email and Password. What I want exactly is If I enter Incorrect Email and Correct password then in Validations it have to show only please enter valid email address.
If I enter correct Email then it has to show please enter correct password. If both are wrong means then it has to show validations please enter correct Email and Password.
This is my code
import React, { useState } from 'react';
import './Login.css';
const Login = () => {
const [loginData, setLoginData] = useState(null)
const loginCredentials = () => {
if (loginData.email === 'john#gmail.com' && loginData.password === 'christina') {
} else {
}
}
const handleChange = ({ target }) => {
const { name, value } = target
const newData = Object.assign({}, loginData, { [name]: value })
setLoginData(newData)
}
const handleSubmit = (e) => {
e.preventDefault()
loginCredentials()
}
return (
<div className='container'>
<div className='row justify-content-center'>
<div className='col-4'>
<div className='mainform mt-3'>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="email">Email</label>
<input type="email" name='email' className="form-control" id="email" onChange={handleChange}></input>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input type="password" name='password' className="form-control" id="password" onChange={handleChange}></input>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div>
)
}
export default Login
Try saving the errors in an array and check the length of array at the end.
const [errors,setErrors]=useState([]);
.
.
.
if(username !='john#gmail.com')
{
setErrors([...errors,{error:'Invalid username'}])
}
if(password!='something')
{
setErrors([...errors,{error:'Invalid password'}])
}
Now inside of the component
{errors?errors.map(elem=>elem.error):null}
You can create a state for the error message and change its value based on what combination of email and password is incorrect. If
const [errorMessage, setErrorMessage] = useState('')
const loginCredentials = () => {
if (loginData.email !== 'john#gmail.com' && loginData.password !== 'christina') {
setErrorMessage('email and pw are both incorrect')
} else if (loginData.email !== 'john#gmail.com' {
setErrorMessage('email is incorrect')
} else if {.....etc
}
then put {errorMessage} in your jsx where you want it to show up
You can use nested if else
const [error, setError] = useState("");
const loginCredentials = () => {
if (loginData.email === "john#gmail.com") {
if (loginData.password === "christina") {
setError("");
return true;
}
else
{
setError("Incorrect Password");
return false;
}
} else {
setError("Incorrect Email and password");
return false;
}
};
To show the error you can put a div somewhere in the form which will only show when there is error.
{error && <div>{error}</div>}
First of all, your input values are not controlled elements. learn about 'controlled component'.
There are lots of ways you can achieve this.
I think you can add a custom hook to handle onChange and reset handler.
custom hook:
import { useState } from 'react';
const useInputState = (initialValues) => {
const [state, setstate] = useState(initialValues);
const onChangeHandler = (e) => setstate({
...state,
[e.target.name]: e.target.value,
});
const reset = (field) => {
if (field) {
setstate({
...state,
[field]: initialValues[field],
});
} else {
setstate({
...initialValues,
});
}
};
return [state, onChangeHandler, reset];
};
export default useInputState;
Then consume that hook in your component.
import React, { useState } from 'react';
import UseInputState from '../hooks/useInputState';
const App = () => {
const [value, onChangeHandler, reset] = UseInputState('');
console.log({ value });
const [emailAlert, setEmailAlert] = useState(null);
const [passwordAlert, setPasswordAlert] = useState(null);
const loginCredentials = () => {
setEmailAlert(null);
setPasswordAlert(null);
const { email, password } = value;
if (email !== 'john#gmail.com') {
setEmailAlert('Please Enter valid Email Address');
}
if (password !== 'christina') {
setPasswordAlert(' please enter correct password');
}
reset('');
if (password === 'christina' && email === 'john#gmail.com') {
setEmailAlert(null);
setPasswordAlert(null);
}
};
const handleSubmit = (e) => {
e.preventDefault();
loginCredentials();
};
return (
<div className='container'>
<div className='row justify-content-center'>
<div className='col-4'>
<div className='mainform mt-3'>
<form onSubmit={handleSubmit}>
<div className='form-group'>
<label htmlFor='email'>Email</label>
<input
type='email'
name='email'
className='form-control'
id='email'
value={value.email || ''}
onChange={onChangeHandler}
></input>
</div>
<div className='form-group'>
<label htmlFor='password'>Password</label>
<input
type='password'
name='password'
className='form-control'
id='password'
value={value.password || ''}
onChange={onChangeHandler}
></input>
</div>
<button type='submit' className='btn btn-primary'>
Submit
</button>
</form>
{emailAlert && <div>{emailAlert}</div>}
{passwordAlert && <div>{passwordAlert}</div>}
</div>
</div>
</div>
</div>
);
};
export default App;

Resources