jaredpalmer / formik

Build forms in React, without the tears 😭
https://formik.org
Apache License 2.0
33.98k stars 2.79k forks source link

Allow the passing of decorators to useFormik #2354

Open davidroeca opened 4 years ago

davidroeca commented 4 years ago

🚀 Feature request

The following feature request proposes customization of the lower-level useFormik function. Currently, setFieldValue and setValues are relied upon by formik's internals to do a slew of interesting things. Unfortunately, it's not quite possible to change formik's setFieldValue and setValues behavior to implement something like undo, or to listen to form-level value changes cleanly.

This proposal merely requests the option to add decorators to a number of set* and setField* functions so that users who desire more functionality out of formik can get it while still preserving the same context API.

Current Behavior

Mostly taken from here:


function useFormikModified(props) {

  const {
    setValues: internalSetValues,
    setFieldValues: internalSetFieldValues,
    ...formik,
  } = useFormik(props)
  const setValues = (values, shouldValidate) => {
    console.log('Decorated setValues!')
    return internalSetValues(values, shouldValidate)
  }
  const setFieldValue = (field, value, shouldValidate) => {
    console.log('Decorated setFieldValue!')
    return internalSetFieldValue(field, value, shouldValidate)
  }
  return { ...formik, setValues, setFieldValues }
}

However, unfortunately, this functionality doesn't override the internals that rely on the old version of setFieldValue and setValues, namely:

And all other functions/properties that rely on these.

Desired Behavior

Define a way for these functions to change behavior slightly, and then pass it into useFormik.

function useFormikModified(props) {
  const decoratedSetValues = (setValues) => (values, shouldValidate) => {
    console.log('Decorated setValues!')
    return setValues(values, shouldValidate)
  }
  const decoratedSetFieldValue = (setFieldValue) => (field, value, shouldValidate) => {
    console.log('Decorated setFieldValue!')
    return setFieldValue(field, value, shouldValidate)
  }
  return useFormik({ ...props, decorators: { decoratedSetValues, decoratedSetFieldValue }})
}

Suggested Solution

Provide this decorator interface as optional for the set* methods by enhancing the useFormik interface. If the decorators aren't defined, then functionality remains the same as it is now.

Who does this impact? Who is this for?

Any advanced user who needs additional functionality out of formik.

Describe alternatives you've considered

I've tried listening to changes of values in the useFormikContext but I can't track which field was precisely changed in this case. All I get is the entire values object and no info on which value was changed.

An alternative to this feature could be handled by: https://github.com/jaredpalmer/formik/issues/1854#issuecomment-596601127

Additional context

See Discussion in https://github.com/jaredpalmer/formik/issues/2339

johnrom commented 4 years ago

I still recommend allowing users to pass in a custom reducer that supports subscriptions instead of overriding internal functionality directly, as mentioned in the alternatives.