How to populate fields in reactjs formik - reactjs

I'm new to formik and i am trying to populate an edit page where users can edit existing fields with formik. I keep getting React Hook "useEffect" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks error. I used the react useEffect hook to try and get the data from the backend.
function Edit({ history, match }) {
const { id } = match.params;
const isAdd = !id;
const initialValues = {
firstName: '',
lastName: '',
};
const validationSchema = Yup.object().shape({
firstName: Yup.string()
.required('First Name is required'),
lastName: Yup.string()
.required('Last Name is required'),
});
return (
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={()={}}>
{({ errors, touched, isSubmitting, setFieldValue }) => {
useEffect(() => {
if (!isAdd) {
getById(id).then(user => {
const fields = ['firstName', 'lastName'];
fields.forEach(field => setFieldValue(field, user[field], false));
});
}
}, []);
return (
<Form>
<div className="form-group col-5">
<label>First Name</label>
<Field name="firstName" type="text" className={'form-control' +
(errors.firstName && touched.firstName ? ' is-invalid' : '')} />
<ErrorMessage name="firstName" component="div" className="invalid-
feedback" />
</div>
<div className="form-group col-5">
<label>Last Name</label>
<Field name="lastName" type="text" className={'form-control' +
(errors.lastName && touched.lastName ? ' is-invalid' : '')} />
<ErrorMessage name="lastName" component="div" className="invalid-
feedback" />
</div>
</div>
</Form>
);
}}
</Formik
)}
export { Edit };

Related

How to solve uncontrolled warning in react formik?

Let's say we have a form that has two fields, first name, and last name.
I want to control this form using React Formik and I have simulated API response using setTimeout
The problem is that when API returns null for some properties, I get the dirty uncontrolled warning of React.
I'm using Formik's 'name' prop to mutually bind my JSON to my form inputs.
How can I solve this problem?
Here's my code:
export default function Home() {
const [initialValues, setInitialValues] = useState({
firstName: '',
lastName: '',
});
useEffect(() => {
console.log(initialValues);
}, [initialValues]);
useEffect(() => {
setTimeout(() => {
setInitialValues({ firstName: 'api', lastName: null });
}, 3000);
}, []);
const onSubmit = (values) => {
console.log(values);
};
const validationSchema = Yup.object({
firstName: Yup.string().required('Required'),
lastName: Yup.string().required('Required'),
});
return (
<div>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
validateOnChange={false}
validateOnBlur={false}
enableReinitialize
>
<Form>
<br />
<div>
<Field
type="text"
id="firstName"
name="firstName"
label="firstName"
placeholder="First Name"
/>
<ErrorMessage name="firstName" />
</div>
<br />
<div>
<Field
type="text"
id="lastName"
name="lastName"
placeholder="Last Name"
/>
<ErrorMessage name="lastName" />
</div>
<br />
<button type="submit">Submit</button>
</Form>
</Formik>
</div>
);
}
And here's an online sample in StackBlits
Don't trust the data coming back from your API to be complete, then. Pull each value you need into a new object with a default value of an empty string. Something like
let newInitialValues = {};
newInitialValues.firstName = apiResult.firstName ? apiResult.firstName : '';
newInitialValues.lastName = apiResult.lastName ? apiResult.lastName : '';
This ensures you'll always have a valid value.

Form data filled does not show on console using react hooks

I have a form built with formik and yup, but after filling the form, the data did not show on the console and when i clicked the next button, it does not take to the next page.
The validations are working.
.
.
.
const navigate = useNavigate()
const initialValues = {
phone: "",
email: ""
}
const validationSchema = Yup.object({
phone: Yup.string().required('Required'),
email: Yup.string().required('Required').email('Invalid email format'),
})
const onSubmit = values => {
console.log('Form data', values)
navigate("/NextPage")
}
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}>
<Form>
<div className="mb-3">
<label className='form-label'>Phone Number</label><br/>
<Field type='tel' name='phone' className='place-holder white-bg' id='phone'/>
<ErrorMessage name='phone'>
{ (errorMsg) => <div className='error'>{errorMsg}</div> }
</ErrorMessage>
</div>
<div className="mb-3">
<label className='form-label'>Email address(optional)</label><br/>
<Field type='email' name='email' className='place-holder white-bg' id='email'/>
<ErrorMessage name='email'>
{ (errorMsg) => <div className='error'>{errorMsg}</div> }
</ErrorMessage>
</div>
<Button variant="primary" type="submit" className="buy-token-next-btn">
Next
</Button>
</Form>
</Formik>

onchange in a form using formik the value of the field is not updated

I'm new to react, and I'm trying to apply validations to a form.
For some reason when adding the property:
onChange={onChange}
I want to send the values to the parent component. That's why I'm using the onchange.
Nothing I write is shown in my text fields, why does this happen?
export const Son = props => {
const { onChange } = props;
return (
<Formik
initialValues={{
fullname: "",
email: ""
}}
validationSchema={Yup.object().shape({
fullname: Yup.string()
.min(2, "Your name is too short")
.required("Please enter your full name"),
email: Yup.string()
.email("The email is incorrect")
.required("Please enter your email")
})}
onSubmit={(values, { setSubmitting }) => {
const timeOut = setTimeout(() => {
console.log(values);
setSubmitting(false);
clearTimeout(timeOut);
}, 1000);
}}
>
{({
values,
errors,
touched,
handleSubmit,
isSubmitting,
validating,
valid
}) => {
return (
<Form name="contact" method="post" onSubmit={handleSubmit}>
<label htmlFor="fullname">
Fullname
<Field
type="text"
name="fullname"
autoComplete="name"
placeholder="your fullname"
onChange={onChange}
/>
</label>
{<ErrorMessage name="fullname">{msg => <p>{msg}</p>}</ErrorMessage>}
{/*errors.fullname && touched.fullname && <p>{errors.fullname}</p>*/}
<br />
<label htmlFor="email">
Email
<Field
type="email"
name="email"
autoComplete="email"
placeholder="your email"
onChange={onChange}
/>
</label>
<ErrorMessage name="email">{msg => <p>{msg}</p>}</ErrorMessage>
<br />
<button type="submit" disabled={!valid || isSubmitting}>
{isSubmitting ? `Submiting...` : `Submit`}
</button>
</Form>
);
}}
</Formik>
);
};
this is my live code:
https://stackblitz.com/edit/react-qotvwb?file=components/son_component.js
you're not using the formik handleChange at all.
I highlighted the changes that I made in https://stackblitz.com/
and you can test this working here

Submitting Formik form data to firebase database in react

I am trying to figure out how to send form data form a Formik form to a Firebase database in my react app.
I have a form as follows:
import React from 'react'
import { Link } from 'react-router-dom'
// import { Formik } from 'formik'
import { Formik, Form, Field, ErrorMessage, withFormik } from 'formik';
import * as Yup from 'yup';
import { Badge, Button, Col, Feedback, FormControl, FormGroup, FormLabel, InputGroup } from 'react-bootstrap';
import Select from 'react-select';
import firebase from '../../../firebase';
const style1 = {
width: '60%',
margin: 'auto'
}
const style2 = {
paddingTop: '2em',
}
const style3 = {
marginRight: '2em'
}
const style4 = {
display: 'inline-block'
}
const options = [
{ value: 'author', label: 'Author' },
{ value: 'reviewer', label: 'Reviewer' },
];
class Basic extends React.Component {
state = {
selectedOption: null,
}
handleChange = (selectedOption) => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
}
render() {
const { selectedOption } = this.state;
return (
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
password: '',
confirmPassword: '',
selectedOption: null
}}
validationSchema={Yup.object().shape({
firstName: Yup.string()
.required('First Name is required'),
lastName: Yup.string()
.required('Last Name is required'),
email: Yup.string()
.email('Email is invalid')
.required('Email is required'),
selectedOption: Yup.string()
.required('It will help us get started if we know a little about your background'),
password: Yup.string()
.min(6, 'Password must be at least 6 characters')
.required('Password is required'),
confirmPassword: Yup.string()
.oneOf([Yup.ref('password'), null], 'Passwords must match')
.required('Confirm Password is required')
})}
// onSubmit={fields => {
// alert('SUCCESS!! :-)\n\n' + JSON.stringify(fields, null, 5))
// }}
// onSubmit={handleSubmit}
render={({ errors, status, touched }) => (
<Form style={style1}>
<h1 style={style2}>Get Started</h1>
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<Field name="firstName" type="text" className={'form-control' + (errors.firstName && touched.firstName ? ' is-invalid' : '')} />
<ErrorMessage name="firstName" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" type="text" className={'form-control' + (errors.lastName && touched.lastName ? ' is-invalid' : '')} />
<ErrorMessage name="lastName" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<Field name="email" type="text" placeholder="Please use your work email address" className={'form-control' + (errors.email && touched.email ? ' is-invalid' : '')} />
<ErrorMessage name="email" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<Field name="password" type="password" className={'form-control' + (errors.password && touched.password ? ' is-invalid' : '')} />
<ErrorMessage name="password" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="confirmPassword">Confirm Password</label>
<Field name="confirmPassword" type="password" className={'form-control' + (errors.confirmPassword && touched.confirmPassword ? ' is-invalid' : '')} />
<ErrorMessage name="confirmPassword" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="selectedOption">Which role best describes yours?</label>
<Select
value={selectedOption}
onChange={this.handleChange}
options={options}
/>
</div>
<div className="form-group" >
<label htmlFor="consent">By registering you accept the <Link to={'/Terms'}>Terms of Use</Link> and <Link to={'/Privacy'}>Privacy Policy</Link> </label>
</div>
<div className="form-group">
<Button variant="outline-primary" type="submit" style={style3} id="submitRegistration">Register</Button>
</div>
</Form>
)}
/>
);
}
}
export default Basic;
I have a database in firebase (cloud firestore) with a collection called Registrations that has fields named the same as each of these form fields.
I have spent the day following tutorials that seem to be made for react before Formik. There's not much point to showing all the things I've tried and failed at for the day - they're clearly not written with Formik in mind. I can't find a way to write the onSubmit so that Formik can give the data to Firebase.
Has anyone found a current tutorial or know how to do this?
I've used Formik and Firebase in this Open-Source React project. Maybe this is what you're looking for :)
Expertizo React Native Kit

Is it possible to timeout and hide the error message of forms after some time in Formik?

How can I hide the error message of forms after some time in Formik (React form library).
Is there any method in Formik?
It shows Name is Required, Email is required, Message is required. But I want to hide it after sometime.
Here is my code :
import React from 'react';
import { withFormik, Form, Field } from 'formik';
import * as Yup from 'yup';
import './contact.scss';
const Contact = ({ errors, touched }) => {
return (
<section className="c-section c-contact u-padding-v-xlarge">
<h1>Get in touch</h1>
<p>We&apos;ll love to hear from you!</p>
<Form>
<div>
{touched.name && errors.name ? (
<p style={{ color: 'red' }}>{errors.name}</p>
) : null}
<Field
id="Name"
type="text"
name="name"
autoComplete="name"
placeholder="Your Name"
/>
</div>
<div>
{touched.email && errors.email ? (
<p style={{ color: 'red' }}>{errors.email}</p>
) : null}
<Field
id="message"
type="email"
name="email"
autoComplete="email"
placeholder="Your Email"
/>
</div>
<div>
{touched.message && errors.message ? (
<p style={{ color: 'red' }}>{errors.message}</p>
) : null}
<Field
component="textarea"
name="message"
id="message"
placeholder="Your Message"
/>
</div>
<button type="submit" className="button button--success button--block">
Send Message
</button>
</Form>
</section>
);
};
export default withFormik({
mapPropsToValues: () => ({
name: '',
email: '',
message: '',
}),
validationSchema: Yup.object().shape({
name: Yup.string().required('Name is required'),
email: Yup.string()
.email('Email not valid')
.required('Email is required'),
message: Yup.string().required('Message is required'),
}),
handleSubmit: (values, { resetForm }) => {
// Handle http request here
console.log(values);
setTimeout(resetForm(), 2000);
},
})(Contact);
I have tried setTimeout(resetForm(), 2000); passing resetForm but it doesn't work. Any alternative?
When you do setTimeout(resetForm(), 2000) you are not passing the function (you are calling it) to the setTimeout. You should do setTimeout(resetForm, 2000). If you want to reset errors you can use setErrors like in example https://codesandbox.io/s/941jzvx01p

Resources