How to 'useState' correctly in Formik 'onSubmit' function? - javascript

I'm using Formik in my Next.js app, and i ran into a problem that I'm not sure how to fix. My submit Button is a component that accepts a showSpinner prop. If it is true -> button is disabled and a loading spinner in a button is displayed. showSpinner value depends on loading that is coming from useState hook. Here is a relevant code:
export default function register() {
const [loading, setLoading] = useState(false)
return (
<>
<Layout>
<div className={styles.registerContainer}>
<div className={styles.registerFormContainer}>
<h1 className={styles.registerHeader}>Sign Up</h1>
<Formik
initialValues={{
email: '',
password: '',
passwordConfirm: '',
acceptedTerms: false
}}
onSubmit={
(values, { setSubmitting }) => {
console.log(loading)
// here loading == false as expected
setLoading(true)
console.log(loading)
// here loading == false even though i set it to true
initFirebase()
firebase.auth().createUserWithEmailAndPassword(values.email, values.password)
.then((res) => {
console.log('done!')
})
.catch(function (error) {
// Handle Errors here.
console.log(error)
})
.finally(() => {
console.log(loading)
//here loading == false too, even though I expected it to be true
setSubmitting(false)
setLoading(false)
})
}
}
>
<Form>
<FormikText label="Email:"
name="email"
type="email"
id="email" />
<FormikPassword label="Password:"
name="password"
id="password"
/>
<FormikPassword label="Confirm Password:"
name="passwordConfirm"
id="passwordCOnfirm"
/>
<FormikCheckbox
name="acceptedTerms"
id="acceptedTerms"
>
<span className={styles.checkboxLabel}>
I agree to the <Link href="/terms" ><a className={styles.registerLink}>Terms of Service</a></Link> and <Link href="/privacy"><a className={styles.registerLink}>Privacy/Cookie Policy</a></Link>
</span>
</FormikCheckbox>
<div className={styles.buttonContainer}>
<Button type="submit" color="blue" showSpinner={loading}>Sign Up</Button>
</div>
</Form>
</Formik>
</div>
</div>
</Layout>
</>
)
}
Even though my Button is somehow working as expected (spinner is displayed as intended), after console.loging value of loading through onSubmit function call I noticed that it is false were I expected it to be true. Is it due to the way React batches useState calls?
My questions are:
How to handle this scenario in a right way?
If loading == false in those console.logs, why is my Button working as intended ?

is it due to the way React batches useState calls?
I think so, that's precisely why Formik provides a isSubmitting flag, try using it instead of tracking your own loading state, I know it's working for your current specs but you could have some issues when this component gets more complex
Your code would look like this
export default function register() {
return (
<>
<Layout>
<div className={styles.registerContainer}>
<div className={styles.registerFormContainer}>
<h1 className={styles.registerHeader}>Sign Up</h1>
<Formik
initialValues={{
email: "",
password: "",
passwordConfirm: "",
acceptedTerms: false,
}}
onSubmit={async (values) => {
try {
initFirebase();
await firebase
.auth()
.createUserWithEmailAndPassword(
values.email,
values.password
);
} catch (e) {
// Handle Errors here.
console.log(error);
}
}}
>
{({ isSubmitting }) => (
<Form>
<FormikText
label="Email:"
name="email"
type="email"
id="email"
/>
<FormikPassword
label="Password:"
name="password"
id="password"
/>
<FormikPassword
label="Confirm Password:"
name="passwordConfirm"
id="passwordCOnfirm"
/>
<FormikCheckbox name="acceptedTerms" id="acceptedTerms">
<span className={styles.checkboxLabel}>
I agree to the{" "}
<Link href="/terms">
<a className={styles.registerLink}>Terms of Service</a>
</Link>{" "}
and{" "}
<Link href="/privacy">
<a className={styles.registerLink}>
Privacy/Cookie Policy
</a>
</Link>
</span>
</FormikCheckbox>
<div className={styles.buttonContainer}>
<Button
type="submit"
color="blue"
showSpinner={isSubmitting}
>
Sign Up
</Button>
</div>
</Form>
)}
</Formik>
</div>
</div>
</Layout>
</>
);
}
taken from here https://formik.org/docs/examples/async-submission

Related

Reset value of disabled Formik Field

I'm trying to clear/reset the value of a checkbox switch after it becomes disabled. I initially thought I had achieved this by using a React conditional and setting the value to an empty string but if the checkbox had been activated prior to being disabled then that value still gets submitted. This behaviour doesn't seem correct as I was under the impression that disabled input field values do not get submitted?
The React conditional says that if the form is disabled then the value of the checkbox should be empty.
I am using Formik to process forms with Yup schema validation.
Below is my entire code for the form.
Thank you, in advance.
import axios from "axios";
import * as Yup from "yup";
import Head from "next/head";
import Link from "next/link";
import Router from "next/router";
import { useState } from "react";
import Error from "../components/error";
import Layout from "../components/layout";
import Button from "react-bootstrap/Button";
import Spinner from "react-bootstrap/Spinner";
import { Formik, Form, Field, ErrorMessage } from "formik";
var instagram = false;
var twitter = false;
var github = false;
const validationSchema = Yup.object({
firstName: Yup.string()
.max(15, "Must be 15 characters or less"),
email: Yup.string().email("Invalid email address").required("Required"),
username: Yup.string()
.test(
'valid-instagram', "Instagram: may contain only alphanumeric characters, periods, and underscores", function (username){
var instagramRegex = new RegExp(/^(?!.*\.\.)(?!.*\.$)[^\W][\w.]{0,29}$/);
var instagramRes = instagramRegex.test(username)
if (instagramRes) { // if res is true then the username is valid and the switch can be enabled
instagram = false;
return true // return true to tell Yup the field is valid
} else {
instagram = true;
return true // true removes error message
}
}
)
.test(
'valid-twitter', "Twitter: may only contain alphanumeric characters or underscores", function (username){
var twitterRegex = new RegExp(/^[A-Za-z0-9_]{1,15}$/);
var twitterRes = twitterRegex.test(username)
if (twitterRes) { // if res is true then the username is valid and the switch can be enabled
twitter = false;
return true // return true to tell Yup the field is valid
} else {
twitter = true;
return true // true removes error message
}
}
)
.test(
'valid-github', "GitHub: may only contain alphanumeric characters or single hyphens", function (username){
var githubRegex = new RegExp(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i);
var githubRes = githubRegex.test(username)
if (githubRes) { // if res is true then the username is valid and the switch can be enabled
github = false;
return true // return true to tell Yup the field is valid
} else {
github = true;
return true // true removes error message
}
}
)
.required("Required"),
acceptTerms: Yup.boolean()
.required("Required")
.oneOf([true], "You must accept the terms and conditions."),
switchGroup: Yup.array().required("At least one option must be selected"),
});
const initialValues = {
firstName: "",
email: "",
username: "",
acceptTerms: false, // added for our checkbox
switchGroup: [], // array for switches
};
export default function Signup() {
const [error, setError] = useState("");
return (
<Layout>
<Head>
<title>Signup - Notify.is</title>
</Head>
<div className="container-center">
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={async (values, { setSubmitting }) => {
const data = new URLSearchParams(values);
const res = await axios
.post("http://localhost:8080/api/signup", data)
.then((response) => {
Router.push("/thanks");
})
.catch((error) => {
setError(error.message);
});
setSubmitting(false);
}}
>
{({ touched, errors, isSubmitting }) => (
<Form className="form">
<h1 className="display-4 pb-3">Get notified</h1>
<div className="form-label-group">
<Field
type="text"
name="firstName"
id="firstName"
placeholder="First name"
className={`form-control ${
touched.firstName && errors.firstName
? "is-invalid"
: null
}`}
/>
<label htmlFor="firstname">First name</label>
<small id="nameHelp" className="form-text text-muted">
Optional
</small>
</div>
<div className="form-label-group">
<Field
type="email"
name="email"
id="email"
placeholder="Email address"
className={`form-control ${
touched.email && errors.email ? "is-invalid" : null
}`}
/>
<ErrorMessage
component="div"
name="email"
className="invalid-feedback"
/>
<small id="emailHelp" className="form-text text-muted">
We'll never share your email with anyone else.
</small>
<label htmlFor="email">Email address</label>
</div>
<div className="form-label-group">
<Field
type="text"
name="username"
id="username"
autoCorrect="off"
autoCapitalize="none"
placeholder="Username"
className={`form-control ${
touched.username && errors.username ? "is-invalid" : null
}`}
/>
<ErrorMessage
component="div"
name="username"
className="invalid-feedback"
/>
<small id="usernameHelp" className="form-text text-muted">
The unavailable username you want.
</small>
<label htmlFor="username">Username</label>
</div>
<div>
<div className="custom-control custom-switch">
<Field
type="checkbox"
name="switchGroup"
id="instagram-switch"
value={instagram ? "" : "instagram"}
disabled={instagram}
className={`custom-control-input ${
touched.switchGroup && errors.switchGroup
? "is-invalid"
: null
}`}
/>
<label
className="custom-control-label"
htmlFor="instagram-switch"
>
Instagram
</label>
</div>
<div className="custom-control custom-switch">
<Field
type="checkbox"
name="switchGroup"
id="twitter-switch"
value={twitter ? "" : "twitter"}
disabled={twitter}
className={`custom-control-input ${
touched.switchGroup && errors.switchGroup
? "is-invalid"
: null
}`}
/>
<label
className="custom-control-label"
htmlFor="twitter-switch"
>
Twitter
</label>
</div>
<div className="custom-control custom-switch">
<Field
type="checkbox"
name="switchGroup"
id="github-switch"
value={github ? "" : "github"}
disabled={github}
className={`custom-control-input ${
touched.switchGroup && errors.switchGroup
? "is-invalid"
: null
}`}
/>
<label
className="custom-control-label"
htmlFor="github-switch"
>
GitHub
</label>
<ErrorMessage
component="div"
name="switchGroup"
className="invalid-feedback"
/>
</div>
<small id="usernameHelp" className="form-text text-muted">
The service(s) we should check with.
</small>
</div>
<div className="custom-control custom-checkbox pt-3 mb-1">
<Field
type="checkbox"
name="acceptTerms"
id="acceptTerms"
className={`custom-control-input ${
touched.acceptTerms && errors.acceptTerms
? "is-invalid"
: null
}`}
/>
<label htmlFor="acceptTerms" className="custom-control-label">
By checking this box you agree to our:
</label>
<ErrorMessage
component="div"
name="acceptTerms"
className="invalid-feedback"
/>
</div>
<span className="grey termslabel">
<Link href="/tos">
<a className="terms" target="_blank">
Terms of Use
</a>
</Link>{" "}
and{" "}
<Link href="/privacy">
<a className="terms" target="_blank">
Privacy Policy
</a>
</Link>
</span>
<Button
className="btn-lg btn-primary btn-block mt-4"
variant="primary"
disabled={isSubmitting, error}
type="submit"
>
{isSubmitting && (
<Spinner
as="span"
animation="grow"
size="lg"
role="status"
aria-hidden="true"
/>
)}
{isSubmitting && <span> Submitting...</span>}
{!isSubmitting && <span>Sign up</span>}
</Button>
{error ? <Error error={error} /> : null}
<p className="mt-4 mb-3 text-muted text-center">
© Notify.is 2020
</p>
</Form>
)}
</Formik>
</div>
<style jsx>
{`
.display-4 {
font-weight: 700;
}
.terms {
text-decoration: underline;
}
.terms:hover {
text-decoration: none;
}
`}
</style>
</Layout>
);
}
I ended up managing to do what I wanted in a different way than originally intended, but it works well.
Using the Boolean variables that change value based on whether a field should be disabled, I did an if statement for each one within the Formik onSubmit prop and changed the values within the array at the indexes of the values that should be omitted.
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={async (values, { setSubmitting }) => {
// if the field was disabled then don't submit switch value
if (instagram) {
var i = values.switchGroup.indexOf("instagram");
values.switchGroup[i] = null
}
if (twitter) {
var i = values.switchGroup.indexOf("twitter");
values.switchGroup[i] = null
}
if (github) {
var i = values.switchGroup.indexOf("github");
values.switchGroup[i] = null
}
const data = new URLSearchParams(values);
const res = await axios
.post("/api/signup", data)
.then((response) => {
Router.push("/thanks");
})
.catch((error) => {
setError(error.message);
});
setSubmitting(false);
}}
>
Check out the FieldArray component. Its' render prop provides an arrayHelper for adding/removing values from fieldArrays.

React hook, Invalid hook call error occurs

I am building a project using react hooks but getting this error below.
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
And this is the code below
const authRequest = (e: any) => {
e.preventDefault();
alert('Error!')
const [authRequestState, authRequestTrue] = React.useState(false)
authRequestTrue(true)
}
const renderFormikForm = () => {
return (
<Formik initialValues={{country: '', number: ''}} onSubmit={(values) => {submitForm(values)}}>
{({ values, errors, touched, handleChange, handleBlur}) => (
<form>
<div className='input-box'>
<p className='input'>
<input type='email' name='email' placeholder='emial' value='libeto#commontown.co'/>
</p>
<p className='input'>
<input type='number' name='number' placeholder='number' value={values.number} onChange={handleChange} style={{width: '50%'}} />
<button onClick={(e) => authRequest(e)}><em><a>Click!!!</a></em></button>
</p>
</div>
</form>
)}
</Formik>
)
}
So basically, functional component renders renderFormikForm component and when I click the button (say Click!!!) onClick triggers authRequest function but instead state is changed, it gives me the error that I mentioned above.
Hooks can only be created inside function components. You need to use useState inside the function component.
Update your code to following:
const renderFormikForm = () => {
const [authRequestState, authRequestTrue] = React.useState(false)
const authRequest = (e: any) => {
e.preventDefault();
alert('Error!')
authRequestTrue(true)
}
return (
<Formik initialValues={{country: '', number: ''}} onSubmit={(values) => {submitForm(values)}}>
{({ values, errors, touched, handleChange, handleBlur}) => (
<form>
<div className='input-box'>
<p className='input'>
<input type='email' name='email' placeholder='emial' value='libeto#commontown.co'/>
</p>
<p className='input'>
<input type='number' name='number' placeholder='number' value={values.number} onChange={handleChange} style={{width: '50%'}} />
<button onClick={(e) => authRequest(e)}><em><a>Click!!!</a></em></button>
</p>
</div>
</form>
)}
</Formik>
)
}
or you can also re-write it as follows:
const authRequest = (e: any, authRequestTrue) => {
e.preventDefault();
alert('Error!')
authRequestTrue(true)
}
const renderFormikForm = () => {
const [authRequestState, authRequestTrue] = React.useState(false)
return (
<Formik initialValues={{country: '', number: ''}} onSubmit={(values) => {submitForm(values)}}>
{({ values, errors, touched, handleChange, handleBlur}) => (
<form>
<div className='input-box'>
<p className='input'>
<input type='email' name='email' placeholder='emial' value='libeto#commontown.co'/>
</p>
<p className='input'>
<input type='number' name='number' placeholder='number' value={values.number} onChange={handleChange} style={{width: '50%'}} />
<button onClick={(e) => authRequest(e, authRequestTrue)}><em><a>Click!!!</a></em></button>
</p>
</div>
</form>
)}
</Formik>
)
}
The latter one is more closer to the code mentioned in question.
Hope it helps. Revert for any doubts.

Conditionally render empty div or error with React & Bootstrap

I'm setting up a signup form that displays errors below the input fields if the user makes a mistake. The way I have it setup right now, the form will add a div with the error below when the user tries to submit their info. My issue is that when there's an error, it adds the div and messes up the layout of the form because it has to move everything to make space for each error. Is there a way to just have an empty div there if there isn't any errors so that it doesn't mess with the layout when there is one? So like, instead of having margin for spacing between fields, it's an empty div for the errors.
import React, { Component } from "react";
import axios from "axios";
import classnames from "classnames";
import "./Signup.css";
class Signup extends Component {
constructor() {
super();
this.state = {
username: "",
email: "",
password: "",
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onSubmit(e) {
e.preventDefault();
const newUser = {
username: this.state.username,
email: this.state.email,
password: this.state.password
};
axios
.post("api/users/register", newUser)
.then(res => console.log(res.data))
.catch(err => this.setState({ errors: err.response.data }));
}
render() {
const { errors } = this.state;
return (
<div className="signup-form">
<form noValidate onSubmit={this.onSubmit}>
<h2>Sign Up</h2>
<p>It's free and only takes a minute.</p>
<hr />
<div className="form-group">
<label>Username</label>
<input
type="text"
name="username"
className={classnames("form-control form-control-md", {
"is-invalid": errors.username
})}
value={this.state.username}
onChange={this.onChange}
/>
{errors.username && (
<div className="invalid-feedback">{errors.username}</div>
)}
</div>
<div className="form-group">
<label>Email</label>
<input
type="text"
name="email"
className={classnames("form-control form-control-md", {
"is-invalid": errors.email
})}
value={this.state.email}
onChange={this.onChange}
/>
{errors.email && (
<div className="invalid-feedback">{errors.email}</div>
)}
</div>
<div className="form-group">
<label>Password</label>
<input
type="text"
name="password"
className={classnames("form-control form-control-md", {
"is-invalid": errors.password
})}
value={this.state.password}
onChange={this.onChange}
/>
{errors.password && (
<div className="invalid-feedback">{errors.password}</div>
)}
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary btn-block btn-lg">
Sign Up
</button>
</div>
<p className="small text-center">
By clicking the Sign Up button, you agree to our <br />
Terms & Conditions, and{" "}
Privacy Policy
</p>
<div className="text-center">
Already have an account? Login here
</div>
</form>
</div>
);
}
}
export default Signup;
Yes, you can use visibility:hidden property of css.
<div style={{ visibility: error.email? 'visible': 'hidden'}}></div>
since visibility always takes up space, in both cases it is visible as well as hidden. so it won't mess with the layout.

"Synchronous XMLHttpRequest on the main thread is deprecated" error after authentication and redirect in reactjs

I'm working on a react application wherein a user can register, and upon registering, the user would then be redirected to the home page.
Below is how I currently have my code.
The problem is after the user submits the registration form and the registration is successful, once the user is redirected I get the following warning message in the browser console:
[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
I tried two ways of redirecting, using history.push (passed as a prop from the Route component), and using the Redirect component once I update the state and RegisterForm is rerendered. The warning message is displayed regardless of which method I use.
My question is what am I doing wrong, and how do I fix this problem?
I've seen a lot of other questions regarding this issue, but they mostly just describe why this warning is getting displayed, but not necessarily how to fix the issue causing the warning.
class RegisterForm extends React.Component {
constructor(props) {
super(props);
this.state = {
loggedIn: false,
username: '',
email: '',
password: '',
passwordConfirmation: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const target = event.target;
const name = target.name;
const value = target.value;
this.setState({
[name]: value
});
}
handleSubmit(event) {
axios.post('/users/register', {
email: this.state.email,
username: this.state.username,
password: this.state.password,
password_confirmation: this.state.passwordConfirmation,
})
.then(response => {
// const history = this.props.history;
// history.push('/');
this.setState({
loggedIn: response.data.authenticated
});
})
.catch(error => {
console.log('Error registering user.');
});
event.preventDefault();
}
render() {
const loggedIn = this.state.loggedIn;
if (loggedIn) {
return <Redirect push to="/" />
}
return (
<form onSubmit={this.handleSubmit}>
<div>
<label htmlFor="email">Email:</label>
<input type="email" id="email" name="email" value={this.state.email} onChange={this.handleChange} />
</div>
<div>
<label htmlFor="username">Username:</label>
<input type="text" id="username" name="username" minLength="3" maxLength="31" value={this.state.username} onChange={this.handleChange} />
</div>
<div>
<label htmlFor="password">Password:</label>
<input type="password" id="password" name="password" minLength="6" value={this.state.password} onChange={this.handleChange} />
</div>
<div>
<label htmlFor="passwordConfirmation">Confirm Password:</label>
<input type="password" id="passwordConfirmation" name="passwordConfirmation" minLength="6" value={this.state.passwordConfirmation} onChange={this.handleChange} />
</div>
<button type="submit">Register</button>
</form>
);
}
}
function Register(props) {
return (
<div>
<h1>Register</h1>
<RegisterForm history={props.history} />
</div>
);
}
function App() {
return (
<div>
<Router>
<Header />
<Switch>
<Route path="/register" component={Register} />
<Route path="/" component={Home} />
</Switch>
</Router>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('app'));

Make Invalid Validation Disappear After 5 Seconds --ReactJS--

I'm trying to make the invalid feedback validation disappear after being on the screen for 5 seconds. in my state i have an empty errors object, when the form is submitted, the api call catches any errors from the backend, and they are placed in the errors object, the inputs use conditionals based on the errors object to show the validation. I've tried creating a setTimeout function that sets the state to an empty object after 5 seconds, but this causes breaking glitches if the form is submitted again incorrectly. Any insights how I can do this?
Register.js
import React, { Component } from "react";
import axios from 'axios';
import classnames from 'classnames';
class Register extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
password: "",
password2: "",
errors: {}
};
this.onChange = this.onChange.bind(this);
}
onChange(e) {
// THIS FUNCTION MUST BE BOUND -SEE ABOVE BIND
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit = e => {
// ARROW FUNCTIONS DO NOT NEED TO BE BOUND
e.preventDefault();
const newUser = {
name: this.state.name,
email: this.state.email,
password: this.state.password,
password2: this.state.password2
};
this.setState({
email: "",
name: "",
password: "",
password2: ""
});
axios
.post("/api/users/register", newUser)
.then(res => console.log(res.data))
.catch(err => this.setState({ errors: err.response.data }));
};
render() {
const { errors } = this.state;
return (
<div>
<div className="register">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h1 className="display-4 text-center text-dark">Sign Up</h1>
<p className="lead text-center">Create your DevMuse account</p>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<input
type="text"
className={classnames("form-control form-control-lg", {
"is-invalid": errors.name
})}
placeholder="Name"
name="name"
value={this.state.name}
onChange={this.onChange}
/>
{errors.name && (
<div className="invalid-feedback">{errors.name}</div>
)}
</div>
<div className="form-group">
<input
type="email"
className={classnames("form-control form-control-lg", {
"is-invalid": errors.email
})}
placeholder="Email Address"
name="email"
value={this.state.email}
onChange={this.onChange}
/>
{errors.email ? (
<div className="invalid-feedback">{errors.email}</div>
) : (
<small className="form-text text-muted text-center">
This site uses Gravatar so if you want a profile image,
use a Gravatar email
</small>
)}
</div>
<div className="form-group">
<input
type="password"
className={classnames("form-control form-control-lg", {
"is-invalid": errors.password
})}
placeholder="Password"
name="password"
value={this.state.password}
onChange={this.onChange}
/>
{errors.password && (
<div className="invalid-feedback">{errors.password}</div>
)}
</div>
<div className="form-group">
<input
type="password"
className={classnames("form-control form-control-lg", {
"is-invalid": errors.password2
})}
placeholder="Confirm Password"
name="password2"
value={this.state.password2}
onChange={this.onChange}
/>
{errors.password2 && (
<div className="invalid-feedback">{errors.password2}</div>
)}
</div>
<input
type="submit"
className="btn btn-info btn-block mt-4"
/>
</form>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Register;
Just clear any existing timeout before you initiate a new timeout:
componentWillUnmount() {
clearTimeout(this.clearError);
}
...
.catch((err) => {
this.setState({ errors: err.response.data });
clearTimeout(this.clearError); // clear previous timeout, if exists
this.clearError = setTimeout(() => {
this.setState({ errors: {} });
}, 5000);
});

Categories

Resources