Open twhitmorenz opened 4 years ago
Also -- there seem to be some rather over-complicated ideas about how to offer 'OnChange' at the Formik level in https://github.com/formium/formik/issues/1633. If you passed the causative event & a Formik instance, handling it would be:
Please don't require yet another layer of overcomplexity (custom Effects, customizing Despatch, custom components) to do what a simple event handler should be able to do.
I've put some more detail on this suggestion in https://github.com/formium/formik/issues/1633#issuecomment-698095706.
Cheers, Tom
Thanks for the write up. I think you’re right. Initially, Field was a just a simple way to save some key strokes. It wasn’t supposed to do anything fancy other than get the change and blur handlers and the value.
A solution I’d like to explore to steal wrapEvent() function from Reach UI which when passed an event handler will call it after the callback (which is I think the behavior you’re describing).
onChange at the Formik level is a slightly different can of worms. In the future, we will suggest either breaking out useFormik + useEffect + FormikProvider into its own component (so we can optimize rerenders) or using one of the forthcoming selectors in #2746
I think we need to allow a full override of onChange, because that is the purpose of the prop. Augmenting onChange is only one use case. In my opinion, conveniences to allow a user to augment onChange should come in the form of access to the original onChange handler, whch I believe are already exposed via useField
or useFormikContext
. We can definitely make it more intuitive to use, but I think the API should be a declarative one where the developer specifies the order of operations explicitly.
@twhitmorenz one solution to your problem is to pass Formik's handleChange to your change handler. It's not perfect because onChange will change on every render, causing Field to re-render on every change. This is why there's generally another component which subscribes to state which memoizes the change handler. This API needs significant improvement.
https://codesandbox.io/s/formik-codesandbox-template-forked-01wqz?file=/index.js
You can mix function components and class components. So you could do something like:
const MyWrappedForm = () => {
const formikRef = React.useRef(null);
const handleChange = React.useCallback((event) => {
console.log(event.target.name, "Updated");
formikRef.current?.handleChange(event);
}, []);
return <MyForm formikRef={formikRef} handleChange={handleChange} />;
}
class MyForm {
render() {
return <Formik innerRef={this.props.formikRef}>
<Field onChange={this.props.handleChange} />
</Formik>
}
}
const App = () => <MyWrappedForm />;
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days
I found that Formik
does expose the change handler as a render prop if you render your forms that way.
https://formik.org/docs/api/formik#handlechange-e-reactchangeeventany--void
So you can augment the default change handler with something like this:
const { extraHandler } = props
return (
<Formik>
{props => (
<form onSubmit={props.handleSubmit}>
<input
type="text"
onChange={(event) => {
extraHandler(event)
props.handleChange(event)
}}
onBlur={props.handleBlur}
value={props.values.name}
name="name"
/>
{props.errors.name && <div id="feedback">{props.errors.name}</div>}
<button type="submit">Submit</button>
</form>
)}
}
</Formik>
)
🐛 Bug report
Current Behavior
I'm trying to add an 'onChange' event to a without losing existing behavior to update/ store the field value.
By default if I specify an onChange handler, I silently lose integration with the Formik form.
What I have tried:
I am just finding this (very simple, common & basic) requirement super, super difficult to address. And really I am finding the design of Formik -- function components, no instances -- to greatly hinder the ability to access/ integrate with Formik's existing functionality.
I am preferring to use event handlers rather than coding custom components for Fields etc. I am aware there's a whole route there, where I could probably pickup the Formik Context on instantiation/ render/ whatever and probably be able to use it, but from a simplicity & framework design perspective I really strongly suggest users just be able to use event handlers.
Expected behavior
Any of the following behaviors would be fine:
Reproducible example
https://codesandbox.io/s/formik-codesandbox-template-forked-mnnc6
Suggested solution(s)
I would recommend making the 'onChange' work more easily, either allowing an extra one, exposing it at the level and/ or documenting where to listen to it.
I would ALSO very highly recommend making it easier to access the Formik instance/ or methods. Some possible approaches here:
Please don't assume all your users are (or should be) using 'function components'. As we see here, there seem to be difficult gaps in React with function components in that Refs are not available -- which imposes significant limits & complexity on the ability to interact with functional components. Again, simplicity doesn't argue for developers to have to create a bunch of baroque function syntax to capture the Formik Context (or whatever magic gets passed) as it goes to the children.
Additional context
There are many many many issues & questions raised about how to do this. Despite working at a fast pace, I literally spent hours trying numerous ineffective attempts.
The solutions, documentation & possible answers I reviewed without help included:
Possible solutions might have existed here:
Your environment