RFC: Make Form the context provider #2746
Replies: 10 comments 18 replies
-
I keep thinking, can't we just allow the user to pass
I personally use the |
Beta Was this translation helpful? Give feedback.
-
A third option I've thought about: one shared context. // at root
import { FormikAppProvider } from 'formik'
import { MyApp } from './App'
ReactDOM.render(
<FormikAppProvider>
<MyApp />
</FormikAppProvider>
); // one less import everywhere else
import { useFormik, form } from 'formik'
export const MyApp = () => {
const formik = useFormik({...})
return (
<Form>
<Field />
</Form>
)
} // can now use multiple formiks on same page since
// context is now namespaced instead of shared.
import { useFormik, form } from 'formik'
export const MyApp = () => {
const formik = useFormik({ id: 'a', ...})
// this also just works too
useFormik({ id: 'b', ...})
return (
<>
<Form id="a">
<Field /> // knows to pull from a
</Form>
<Form id="b">
<Field /> // knows to pull from b
</Form>
</>
)
} |
Beta Was this translation helpful? Give feedback.
-
As somebody who just started using formik, proposal 2 is the most declarative and understandable form. It reads as The spread is also an option but imo there is little difference in Having an explicit declarative API goes a long way in providing enough magic to make it work but not too much to make it confusing / hard to grasp whats going on. Saying that |
Beta Was this translation helpful? Give feedback.
-
Very interesting, I did not know about the In my last projects I've already stopped using render props. Instead I'm using small Formik wrappers around my input components and plug it to the context with When I do need access to the values, I access them via the What would that mean in terms of rendering to call the |
Beta Was this translation helpful? Give feedback.
-
Proposal 2 looks so simple to me but can we override it for styling the form element by passing the |
Beta Was this translation helpful? Give feedback.
-
Okay research update: I was doing some recoil-like experiments and came across https://github.com/dai-shi/use-context-selector. It does what you think it does, but within user land (ie. I made a codesandbox that shows off how it effectively optimizes https://codesandbox.io/s/formik-use-context-selector-2-hso7i?file=/src/App.tsx One thing I discovered is that it cannot do the optimization with the Anyways, |
Beta Was this translation helpful? Give feedback.
-
I also just started to use Formik and was using render prop. I was quite excited about using my own custom input primitives as suggested in useField docs but as I went further, I had cases where I needed to use useEffect with values just like how you stated in:
Using this solution, I didn't have to implement many custom primitives for the "same" input type because I can listen for changes on values in the actual form/parent component. Otherwise, I would have to be in the scope of But what you say:
kinda confuses me. Wouldn't having a useEffect in my parent component cause all of the primitives to re-render? So you actually force users to have useEffects in deeper components in specific scenarios by suggesting render prop and that looks more performant to me. |
Beta Was this translation helpful? Give feedback.
-
@jaredpalmer in my experimental PR #2931 @formik/reducer-refs does not share any of the same concerns around re-rendering the Provider and makes it just as performant to use the |
Beta Was this translation helpful? Give feedback.
-
I opt for Proposal 1. Please document the use of I am using it in a UI Template that came with my current project. I have just read your documentation re the use of
However, in your example of Proposal 1 above, you are also using Please help...I'm confused about whether I should be using |
Beta Was this translation helpful? Give feedback.
-
I'm in favor of 3 or 2. They make useFormik look clean to use, which makes it much more viable as a default pattern to recommend. And I do recommend making useFormik a default pattern. Using useFormik can hoist the formik state up from a child of the route to the route itself right next to where the submit handler is implemented. This doesn't allow usage of hooks that use the user-friendly hooks like |
Beta Was this translation helpful? Give feedback.
-
I have been thinking of ways to make Formik and
useFormik
even less verbose recently. My idea is to introduce a new context provider (or document the existing<FormikProvider>
) as the "right" way of using Formik instead of the render prop.Proposal 1: Document
useFormik
+FormikProvider
patternWe probably should do this no matter what, but the idea is that people should use
useFormik
andFormikProvider
together instead of the render prop<Formik>
going forward. This allowsField
and other context based components to be easily used without ceremony or added verbosity. It also lets folks easily do effects withuseEffect
.No changes need to made internally to support this as
FormikProvider
is already exported, we just would need to update the docs.There aren't any downsides to this as this is exactly what the
<Formik>
component does internally. However, I think we can make this even more intuitive and look more like HTML...Proposal 2: Make
Form
a context providerTo further cut down on verbosity, we could allow
<Form>
to render the Context provider. This would save us from several keystrokes and another import. In React DOM, it would still render a<form onSubmit={formik.handleSubmit}>
. In React native, it would just renderchildren
under the provider.External API
Implementation
One thing we would need to do in React Native docs is to state that
<Form>
doesn't render anything and re-iterate thatformik.handleSubmit
still needs to be passed to<Button>
.Proposal 3: Make it a spread
Looking back at my usage of
<Form>
over the years, I can count the number of times I have passed it an additional prop on one hand. And that was just to fix a typescript bug with @types/react. I know typing out<Form formik={formik}>
isn't a lot, but it looks awful. Instead we could make<Form>
accept the spread. In React DOM, we could sniff out the keys of formik context and passing any other props to the rootform
element.Alternative 3a: Keep
<FormikProvider>
and make it a spread.Keep
FormikProvider
but have it take a spread. Less typing. Also works flawlessly in React Native. The downside is that this is another import (4 vs. 3).Wanted to open this up to discussion and gather feedback.
Beta Was this translation helpful? Give feedback.
All reactions