'Formik - Upon component mount select first option in dropdown list
On this StackBlitz:
https://stackblitz.com/edit/react-formik-yup-example-uhdg-4dzpq5?file=Registration.js
I have the following code:
import { ErrorMessage, Field, Form, Formik } from 'formik';
import { get } from 'lodash-es';
import React, { useEffect } from 'react';
import * as Yup from 'yup';
const DropdownListInput = ({ value, children, handleChange }) => {
useEffect(() => {
const firstOptionValue = get(children, '[0].props.value', '');
if (value === '' && firstOptionValue !== '') {
// using setTimeout is a workaround and it should be removed.
setTimeout(() => {
handleChange(firstOptionValue);
}, 0);
}
}, []);
return (
<select value={value} onChange={(e) => handleChange(e.target.value)}>
{children.map(({ props: { value, children: text } }, index) => (
<option value={value} key={index}>
{text}
</option>
))}
</select>
);
};
export default () => {
return (
<Formik
initialValues={{
email: '',
}}
validationSchema={Yup.object().shape({
email: Yup.string()
.required('Email is required.')
.email('Email is invalid.'),
})}
onSubmit={(values, { setSubmitting }) => {
console.log(values);
setSubmitting(false);
}}
enableReinitialize
validateOnMount
>
{(formik) => {
return (
<Form>
<div>
<Field
component={DropdownListInput}
formik={formik}
name="email"
value={formik.values.email}
handleChange={(value) => {
console.log(value);
formik.setFieldValue('email', value);
}}
>
<option value="[email protected]">Bill Bates</option>
<option value="[email protected]">Steve Jobs</option>
<option value="[email protected]">Elon Musk</option>
</Field>
<ErrorMessage name="email">
{(error) => <div style={{ color: '#f00' }}>{error}</div>}
</ErrorMessage>
</div>
<input type="submit" value="Submit" disabled={!formik.isValid} />
</Form>
);
}}
</Formik>
);
};
My problem is: For it to work, I needed to use a setTimeout(...).
I just want to get rid of the setTimeout(...) and just leave the instruction inside of it.
Requirement:
- I need the Submit button to get enabled automatically when the component loads.
- Setting the value for the email has to come from the
DropdownListInputitself similarly to what I currently have on the code above.
Any idea on how to achieve this?
If you want you can post your forked StackBlitz.
Thanks!
Solution 1:[1]
I suggest listening to the change of firstOptionValue, and executing handleChange once it was set.
Suggested modification on DropdownListInput component:
const [firstOptionValue, setFirstOptionValue] = useState('')
useEffect(() => {
setFirstOptionValue(get(children, '[0].props.value', ''));
}, []);
useEffect(() => {
if (value === '' && firstOptionValue !== '') {
handleChange(firstOptionValue);
}
}, [firstOptionValue])
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Andrew Li |
