Formik: withFormik not updating touched object automatically

Created on 30 May 2019  路  5Comments  路  Source: formium/formik

馃悰 Bug report

Current Behavior

I've got a React Native application (0.57.0), using Formik (1.5.7). I've got a component that is a screen (a top-level react-navigation route). The form submit button appears in the header, via the component's static navigationOptions. So I'm using withFormik to make the form's values and touched objects available to the header. The form field values are updating as expected, but the touched object is not updating. (Note: My form component is also wrapped by react-redux connect.)

I've had to create a wrapper around the Formik handleChange method to get them to update properly:

    handleChange = field => (value) => {
        const { setTouched, handleChange, touched } = this.props;

        setTouched({
            ...touched,
            [field]: true,
        });

        handleChange(field)(value);
    }

This seems like a total hack, though it does appear to be working. I'd like to know if anyone knows why this might be happening. If I don't monkey patch handleChange the touched object remains empty when I inspect this.props from anywhere in the component.

Here are some examples of my field components. They are just Picker and TextField components from React Native wrapped in styled-components.

<ProvincePicker
                    value={values.province}
                    placeholder={account.residence}
                    onChange={handleChange('province')}
                    provinces={this.props.provinces}
                    required
                    inline
                    style={styles.provincePickerStyle}
                />

and

                    <PhoneInput
                        onChangeText={handleChange('phone')}
                        value={values.phone}
                        placeholder={phonePlaceholder}
                        required={! this.isPhoneOptional()}
                        style={styles.phoneInputStyle}
                    />

I'm grabbing handleChange and values from this.props, and using withFormik to instantiate the component's form data:

const FormikAccount = withFormik({
    mapPropsToValues: props => pickAccountFields(props.authUser),
})(Account);
export default connect(mapStateToProps, mapDispatchToProps)(FormikAccount);

pickAccountFields just returns an object:

const pickAccountFields = (authUser) => {
    const {
        name, phone, email, province, phone_type: phoneType, patient,
    } = authUser;
    const birthdayAt = new Date(patient.data.birthday_at.date);
    const { gender } = patient.data;

    const [firstName, lastName] = name.split(' ');
    return {
        firstName,
        lastName,
        phone,
        email,
        province,
        phoneType: phoneType || 'mobile',
        birthdayAt,
        gender,
    };
};

Expected behavior

That this.props.touched will automatically update when handleChange is called.

Your environment

| Software | Version(s) |
| ---------------- | ---------- |
| Formik | 1.5.7
| React | 16.5.0
| React-Native | 0.57.0
| npm/Yarn | 1.15.2
| Operating System | MacOS Mojave 10.14.5

User Land Question

Most helpful comment

I came across this because I was having a similar issue with the field name not showing up in the touched object even though I had touched it. Not the exact scenario for you but maybe something helpful in it...

I was using the <Field render={({ field }) => (<CustomInput {...field} />)} /> method, to render a custom input field, and pass the formik field props (onChange, onBlur, name and value) from to the input element rendered in my <CustomInput /> via the { ...field} spread (as documented here).

Digging into the source I found that its the onBlur that ultimately sets the touched status via the executeBlur method here, and in my code I wasn't passing the event object through to on my <CustomInput /> components onBlur handler, (I was just calling onBlur, e.g. onBlur={() => { props.onBlur(); ) which resulted in no event object and therefore no field to use for Formik to know which property was touched. Updating my onBlur prop to `onBlur={(e) => { props.onBlur(e); ) resolved the issue for me.

I don't know much about the ReactNative environment, but maybe the Picker or TextField are not triggering the onBlur (handleBlur/executeBlur in Formik code) 馃 or maybe if they are they're not passing the right event data?

All 5 comments

Any word on this?

I came across this because I was having a similar issue with the field name not showing up in the touched object even though I had touched it. Not the exact scenario for you but maybe something helpful in it...

I was using the <Field render={({ field }) => (<CustomInput {...field} />)} /> method, to render a custom input field, and pass the formik field props (onChange, onBlur, name and value) from to the input element rendered in my <CustomInput /> via the { ...field} spread (as documented here).

Digging into the source I found that its the onBlur that ultimately sets the touched status via the executeBlur method here, and in my code I wasn't passing the event object through to on my <CustomInput /> components onBlur handler, (I was just calling onBlur, e.g. onBlur={() => { props.onBlur(); ) which resulted in no event object and therefore no field to use for Formik to know which property was touched. Updating my onBlur prop to `onBlur={(e) => { props.onBlur(e); ) resolved the issue for me.

I don't know much about the ReactNative environment, but maybe the Picker or TextField are not triggering the onBlur (handleBlur/executeBlur in Formik code) 馃 or maybe if they are they're not passing the right event data?

same issue but in react js

In React Native, handleBlur needs to be called like this in order for touched to be updated. Docs are here: https://jaredpalmer.com/formik/docs/guides/react-native

<TextField 
  onChangeText={handleChange('email')}
  onBlur={handleBlur('email')}
  value={values.email}
/>

@denofprojects I imagine you're having the same problem, but in web. Maybe a third party input? If an event is not being passed back from your component's onBlur, then you'll also need to handleBlur(fieldName).

The same issue, but in reactJs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaredpalmer picture jaredpalmer  路  3Comments

najisawas picture najisawas  路  3Comments

jordantrainor picture jordantrainor  路  3Comments

jaredpalmer picture jaredpalmer  路  3Comments

jaredpalmer picture jaredpalmer  路  3Comments