Formik: e.persist is not a function

Created on 29 Sep 2017  Â·  8Comments  Â·  Source: formium/formik

I use ant-design ui library, and i got this error when i use RadioGroup and Radio

Uncaught TypeError: e.persist is not a function
    at Formik._this.handleChange (formik.es6.js:1110)
    at onChange (UserType.jsx:75)
    at Object.RadioGroup._this.onRadioChange [as onChange] (group.js:80)
    at handleChange (Checkbox.js:166)
    at Object.executeOnChange (LinkedValueUtils.js:132)
    at ReactDOMComponent._handleChange (ReactDOMInput.js:241)
    at Object.ReactErrorUtils.invokeGuardedCallback (ReactErrorUtils.js:69)
    at executeDispatch (EventPluginUtils.js:85)
    at Object.executeDispatchesInOrder (EventPluginUtils.js:108)
    at executeDispatchesAndRelease (EventPluginHub.js:43)
    at executeDispatchesAndReleaseTopLevel (EventPluginHub.js:54)
    at Array.forEach (<anonymous>)
    at forEachAccumulated (forEachAccumulated.js:24)
    at Object.processEventQueue (EventPluginHub.js:254)
    at runEventQueueInBatch (ReactEventEmitterMixin.js:17)
    at Object.handleTopLevel [as _handleTopLevel] (ReactEventEmitterMixin.js:27)
    at handleTopLevelImpl (ReactEventListener.js:72)
    at ReactDefaultBatchingStrategyTransaction.perform (Transaction.js:143)
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:62)
    at Object.batchedUpdates (ReactUpdates.js:97)
    at dispatchEvent (ReactEventListener.js:147)

formik code:

_this.handleChange = function (e) {
            if (isReactNative) {
                if (process.env.NODE_ENV !== 'production') {
                    console.error("Warning: Formik's handleChange does not work with React Native. Use setFieldValue and within a callback instead. For more info see https://github.com/jaredpalmer/formikhttps://github.com/jaredpalmer/formik#react-native");
                }
                return;
            }
            e.persist(); // <---- THIS
            var _a = e.target, type = _a.type, name = _a.name, id = _a.id, value = _a.value, checked = _a.checked, outerHTML = _a.outerHTML;
            var field = name ? name : id;
            var val = /number|range/.test(type)
                ? parseFloat(value)
                : /checkbox/.test(type) ? checked : value;
            if (!field && process.env.NODE_ENV !== 'production') {
                console.error("Warning: You forgot to pass an `id` or `name` attribute to your input:\n\n  " + outerHTML + "\n\nFormik cannot determine which value to update. For more info see https://github.com/jaredpalmer/formik#handlechange-e-reactchangeeventany--void\n");
            }
            _this.setState(function (prevState) {
                return (__assign({}, prevState, { values: __assign({}, prevState.values, (_a = {}, _a[field] = val, _a)) }));
                var _a;
            });
            if (_this.props.validateOnChange) {
                _this.runValidations(__assign({}, _this.state.values, (_b = {}, _b[field] = value, _b)));
            }
            var _b;
        };

example:

const UserTypeForm = ({
    values,
    touched,
    errors,
    dirty,
    handleChange,
    handleBlur,
    handleSubmit,
    handleReset,
    isSubmiting,
    ...props
}) => (
    <Form className={props.className} onSubmit={handleSubmit}>
        <Form.Item
            label="Type"
            required
            validateStatus={touched.type && errors.type ? "error" : ""}
            help={touched.type && errors.type}
        >
            <RadioGroup
                name="type"
                value={values.type}
                onChange={handleChange}  // <--- Here error
            >
                <RadioGroup.Radio value={1}>One</RadioGroup.Radio>
                <RadioGroup.Radio value={2}>Two</RadioGroup.Radio>
                <RadioGroup.Radio value={3}>Three</RadioGroup.Radio>
            </RadioGroup>
        </Form.Item>
        <Form.Item className="next-button">
            <SuccessButton htmlType="submit">
                Save and next
            </SuccessButton>
        </Form.Item>
    </Form>
)

Now i resolve this error by:

onChange={(e) => {
     e.persist = () => {}
     handleChange(e)
}}

Most helpful comment

You will need to wrap the input in its own component treat it like a custom input. Use setFieldValue(this.props.name, value) and you should be good

All 8 comments

You will need to wrap the input in its own component treat it like a custom input. Use setFieldValue(this.props.name, value) and you should be good

@jaredpalmer I ran into the same issue using react-bootstrap, can you give a quick example on how to use setFieldValue as you have suggested above. Much appreciated.

Just like React Native and many third party input components, you may not have access to the synthetic DOM event e. Thus, e.target.name and e.persist() are not available. In these situations, you should use setFieldValue and setFieldTouched.

React Native Formik Docs: https://github.com/jaredpalmer/formik#react-native
Working with 3rd Party Inputs example: https://codesandbox.io/s/jRzE53pqR

Sorry for the disturb, I meet the same case using 3rd party form component(Ant Design), it triggers a React.ChangeEvent<HTMLInputElement> (https://github.com/ant-design/ant-design/blob/master/components/radio/group.tsx#L76) that does not have .persist().

The 3rd party form component provides name attribute allowing setting correct name attribute for form controls, that should be ideal for formik's handleChange() (except the .persist() function).

setFieldValue is working, but I have to specify it on every component's onChange` attribute when using 3rd party component.

I have some ideas:

  • check e.persist() before calling it, and do not call it when not exist. If things still not work properly with handleChange's way of retrieving data, we use setFieldValue
  • allowing provide a custom handleChange, thus we can process a specific 3rd form component's event in a unified way.

I'm also playing with Formik and ant.design (in Typescript) - apart from ant's onChange missing .persist(), the onBlur function passes no arguments (well actually it passes value, but the type definitions say no args).

Creating manual onChange and onBlur is trivial, really... but we're so close to just being able to use formik's 'props.field' values as they are, that it seems a shame.

To build on @frantic1048's idea, I wonder if we could make the code a bit more resilient and increase Formik's utility/compatibility e.g.

  • only call .persist() if it exists,
  • open up the types of onChanged's arguments from React.ChangeEvent to the shape of the actual fields used, such as { target: { name: string, value: any } }.
  • eliminate onBlur's unecessary event argument (if its unnecessary?)

@Martaver according to @whtsky's issue above, ant design's onChange callback event type: React.ChangeEvent` is a FAKE(I was mislead) type declared by ant design. It also misleads tslint so that no error was triggered at compile time. (´_`)

I think formik's handleChange() calls .persist() is okay. Because if the typing is REAL, .persist() should always exist.

So we do not need to check if .persist() exist, it always exists if the typing is TRUE...

Allowing overriding of handleChange() should be enough for such scenario

So is the recommended solution for now doing: onChange={(e) => { e.persist = () => {} handleChange(e) }}?

So is the recommended solution for now doing: onChange={(e) => { e.persist = () => {} handleChange(e) }}?

use setFieldValue method similar to onChange={e => setFieldValue('joinedAt', e)}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jordantrainor picture jordantrainor  Â·  3Comments

najisawas picture najisawas  Â·  3Comments

pmonty picture pmonty  Â·  3Comments

sibelius picture sibelius  Â·  3Comments

ancashoria picture ancashoria  Â·  3Comments