Hoisting Formik values to higher level state - reactjs

In a Formik component, I need one of the values from the values prop to be available outside of the component. Preferably bound to a state variable.
<Formik
initialValues={initialValues}
validationSchema={LocationAddressSchema}
onSubmit={onSubmit}
>
{({ isSubmitting, isValid, values }) => (
<Form>
How can I take what comes back from values.name for example and set it to a state variable so that every time the value of values.name changes the state will re render holding that new value

Did you try this way?
<Formik ...>
...
<input type="text" onChange={props.handleChange} ...>
...
</Formik>

Related

Update Formik's state from a button onClick

I have a Formik form and when I click a button I want to update the form's state.
function updateForm(){
//Update a product in the form's state
}
<Button onClick={updateForm}>Update Product</>
<Formik
initialValues={{ products: {} }}
>
{({values}) = (
)}
</Formik>
I tried to update the initialValues but that will reset any current changes in the form's state.
I could copy the Form's state into a local setState and loop that back into the initialValues but that feels overkill, as Formik does that already.
I thought useFormik might work, but the docs don't expand how this might work...?
Given the helpful comments from #aditaya81070, I eventually landed on this solution...
I also had to refactor my solution a little, because I had two Forms on the page and in order to use setFieldValue I had to nest both Forms within the <Formik> element, so they could communicate easily (they can still have their own state separately). But don't nest them within themselves as that's not allowed.
So this is fine:
<Formik>
<Form />
<Form />
</Formik>
but this is not...
<Formik>
<Form>
<Form />
</Form>
</Formik>
Then I just pass in the setFieldValue into the callback of the button...easy :)
function updateForm(setFieldValue){
//Update a product in the form's state
setFieldValue('product.price'), 1.50);
}
<Formik
initialValues={{ products: {} }}
>
{({values, setFieldValue, validateForm}) = (
<button onClick={() =>
//This is the import bit, to get the context.
updateForm(setFieldValue)
}>
Update Product
<button/>
)}
</Formik>

Is there access to Formik props inside <Field validate>

I have 2 fields. Second field should be auto populated once input of first field is validated OK. In order to populate second field i need to access formik's helper methods, which we normally have inside <Field>.
Portion of code related to formik:
const validateRoutingNumber = (value: string) => {
// props.form.setFieldValue('financialInstitution', 'ANYTHING'); <---- Can do something like this?
return;
}
<Formik initialValues={initialValues} validationSchema={Schema} validateOnMount onSubmit={submitForm}>
<Form>
<Field name="routingNumber" validate={validateRoutingNumber}>
{(props: FieldProps) => (
<TextField
variant="outlined"
{...props.field}
{...textErrors(props.meta)}
type="text"
inputProps={{'aria-label': t('routingNumber')}}
/>
)}
</Field>
Is there a way to access to props inside <Field>, like we do inside <TextField>?
I found out that i can access the desired formik properties. In similar manner how access is provided to formik properties on <TextField> level, access can be provided to <Formik> level using render props tehnique.
Portion of code to provide desired behavior:
const validateRoutingNumber = async (value: string, formikProps: FormikProps<any>) => {
console.log('formikProps', formikProps);
....
}
<Formik initialValues={initialValues} validationSchema={Schema} validateOnMount onSubmit={submitForm}>
{(formikProps: FormikProps<any>) => (
<Form>
<Field name="routingNumber" validate={(value: string) => validateRoutingNumber(value, formikProps)}>
{(props: FieldProps) => (
<TextField
There are nice video materials on youtube regarding formik usage - https://www.youtube.com/watch?v=0TFIBPyitXo

Formik checkbox won't re-render

I am using Formik library and have a simple form with one checkbox that I would like to submit on change:
<Formik
initialValues={{ toggle: false }}
validateOnChange={false}
validateOnBlur={false}
onSubmit={(values, { validateForm }) => {
validateForm().then(_errors => {
console.log(values);
});
}}
>
{({ values, handleChange, handleSubmit }) => (
<div>
<form onChange={handleSubmit}>
<label>
Toggle
<input
name="toggle"
type="checkbox"
checked={values.toggle}
onChange={handleChange}
/>
</label>
</form>
</div>
)}
</Formik>
For some reason, it looks like the input is not being re-render after every click, only after every second click. As a result checkbox is not being update - you have to click twice for it to change (onChange event only fires every second time)
I can force it to re-render by adding key but it's a hack.
Here's the sandbox: https://codesandbox.io/s/formik-checkbox-issue-ew65e
Your problem is that you are trying to submit the form at every change.
Idealy you should debounce this behaviour (using lodash maybe ?) :
import _ from 'lodash'
<form onChange={_.debounce(handleSubmit, 300)}>
Alternatively, if you don't use lodash, you can make the call to handleSubmit asynchronous by wrapping it in a setTimeout like this :
<form onChange={() => setTimeout(handleSubmit, 0)}>

How to handle Formik's `handleChange` prop?

I get it that Field has an onChange attribute where you can pass the own Formik onChange prop from here: https://jaredpalmer.com/formik/docs/api/formik#handlechange-e-reactchangeevent-any-void.
However, I am struggling to understand where these value[key] is passed, so I can handle the data passed in the form. Found in withFormik(): How to use handleChange that I can pass two callbacks to Formik's onChange prop, but I wonder if there is a better way to handle this.
edit after comments from folks that replied, thanks for that:
My code using these 2 callbacks in the onChange prop in Field:
export default function FormikForm() {
const onSubmitHandler = (formValues, actions) => {
console.log(formValues);
console.log(actions);
};
const onChangeHandler = (e) => {
console.log(e.target.value);
};
return (
<div>
<h1>This is the Formik Form</h1>
<Formik
initialValues={{
name: "",
email: "",
age: ""
}}
onSubmit={onSubmitHandler}
render={props => {
return (
<Form>
<label>
Name
<Field
name="name"
type="text"
placeholder="name"
onChange={e => {props.handleChange(e); onChangeHandler(e)}}
/>
</label>
<button type="submit">Submit</button>
</Form>
);
}}
/>
</div>
);
}
Is there a way to do a similar thing as in onSubmitHandler, where Formik automagically outputs the value of the input without having to call these 2 functions in the onChange?
Thanks
Every field component receives a field prop which has a value prop containing the value for that field, as well as a form prop containing helper methods that you can use to set the value. I'd need to see the structure of your code to give specific suggestions on how to implement what you want, but you can emulate the default functionality by calling form.setFieldValue(field.name, field.value). In addition, the field prop has this handler built in by default in the field.onChange prop.

How to use custom Input with Formik in React?

I'm trying to use DatePicker within Formik. But when I click DatePicker's date its form value is not changed. Instead, I got this error:
Uncaught TypeError: e.persist is not a function
at Formik._this.handleChange (formik.es6.js:5960)
I shortify code, the code is below
const SomeComponent = () => (
<Formik
render={({
values,
handleSubmit,
handleChange,
setFieldValue
}) => {
return (
<div>
<form onSubmit={handleSubmit}>
<DatePicker
name={'joinedAt'}
value={values['joinedAt']}
onChange={handleChange}
/>
</form>
</div>
)
}}
/>
)
I googled few documents, https://github.com/jaredpalmer/formik/issues/187 and https://github.com/jaredpalmer/formik/issues/86
So I tried like below, but it's not working.
...setFieldValue
<DatePicker
name={'joinedAt'}
value={values['joinedAt']}
onChange={setFieldValue}
/>
I resolve this like
<DatePicker
name={'joinedAt'}
value={values['joinedAt']}
onChange={e => setFieldValue('joinedAt', e)}
/>
Update on 2020-03-08:
You can use e.target.value on setFieldValue's second prop, depends on your custom input design. Thanks to Brandon.
If you have deeper nesting, you should use Formik Field.
Example:
<Formik
validationSchema={schema}
initialValues={initialValues}
onSubmit={(values, actions) => {}}
>
<Field name="colors" component={ColorsEditor} colors={colorArray}/>
</Formik>
const ColorsEditor = ({ field, colors, form, ...props }) => {
return (
<div>
<Button onClick={() => form.setFieldValue('colors', "myValue")}>
</Button>
</div>
)
}
So the Field component already include the form, where live the setFieldValue that you can use where you need. It also include the errors and needed fields for additional customization.
For html primitive input fields handleChange works like a charm, but for custom components, you've to use setFieldValue to change the value imperatively.
onChange={e => setFieldValue('joinedAt', e)}
The accepted answer didn't work for me and didn't show the selected date. It has been almost a year so there might be some changes with the implementation. Though this can be fix by using toDateString() like this
<DatePicker
name={'joinedAt'}
value={values['joinedAt']}
onChange={e => setFieldValue('joinedAt', e.toDateString())}
/>
The Formik solution for this is the useField() method. You may need to create a wrapper for components like DatePicker that you may not have source access to.
The documentation provides an example:
const MyTextField = ({ label, ...props }) => {
const [field, meta, helpers] = useField(props);
return (
<>
<label>
{label}
<input {...field} {...props} />
</label>
{meta.touched && meta.error ? (
<div className="error">{meta.error}</div>
) : null}
</>
);
};
In short, the method takes in the custom props which describe the field. Then you can expand the assigned field value and props in your custom field.
https://github.com/jaredpalmer/formik/issues/692
you need to set value manually if you are using setFieldValue method

Resources