-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Major gotcha with react/exhaustive-deps #1677
Comments
I don't have a chance to confirm this theory works right now, but if setFieldValue and setFieldTouched are useCallback'd correctly, it should help to depend on those callbacks instead.
I am not against the idea of splitting formikContext into |
@johnrom Yes, you are right, that works, but I wouldn't call it the best solution. You can hardly explain to users that they have to destructure. Personally, I like keeping |
Dang it, I was in the midst of an edit! I like the idea of keeping a stable Formik reference and snapshotting the state. I was responding with a solution because it was marked as bug report. But in terms of requesting a Feature, I'd +1. My .02 on an API:
|
Yea, you are right that it's partially a feature request, but I think many users will come head banging about it being an actual bug. I would not blame them, it's not exactly an easy concept to comprehend. It would be best to figure this out before V2 comes out for sure because it's going to be a breaking change. I am also thinking if |
I think I need to think thru this more |
It shouldn't be actually that hard to achieve. Basically, we need to split the Line 816 in 921ec8d
As long as all API functions are wrapped into Additionally, there could be two hooks |
I think I like the array destructuring better from both a documentation and quality of life point of view, but I have generally embraced the concept of TypeScript tuples so maybe that is really specific to the TS realm. https://www.typescriptlang.org/docs/handbook/basic-types.html#tuple |
Another question I have is whether or not |
Finally, (and sorry for the spam!), I like |
The function references on api object can change, but they need to be stuck to a stable object that will never change. It's kinda funny how hard is to do that. I am using MobX most of the time which builds around mutable and stable object references and it would be super easy to do there. And it would most likely be more performant. But I suppose that would be a completely different project in the end :) Makes more sense like this to me... const [state, api] = useFormikContext()
// these two are optional and can be done in userland
const state = useFormikState()
const api = useFormikApi() |
I disagree and I think there should be a decision between whether API is immutable but changes over time (new object), or all of the functions of the API are designed to never change similar to the |
To add an example given your original post, imagine what happens if
|
@johnrom I don't think it would be a problem in that case. Since the
That's a bad comparison. The dispatch does not rely on a closure state. If you have a function that needs to access a closure variable then anytime that closure variable changes, you need to "refresh" that function so it has access to latest closure. That's why |
Correct me if I’m wrong, but in v1, all fns were like dispatch because they were bound as instance variables on the class. We can use useEventCallback to accomplish this with hooks IIRC. |
@jaredpalmer Those fns are not the problem here, the |
I'm looking through the code now, which I haven't had a chance to before, and I found that setFieldValue is a bad example because it uses
One might consider this incorrect usage, but with immutability or by converting handleChange to use |
Hmm.. we're saying the same thing. I somehow missed this:
And focused on this:
The function references wouldn't change, but the wrapped functions would. So we're arguing the same point. 🤣 |
Right, it needs to be carefully examined which function would go where. The mentioned However, another way could be to basically keep the state object with the |
Checkbox is a bad example because they are now handled by Field in v2. |
@jaredpalmer That was really unnecessary nitpicky comment :) Please let's focus on important discussion. Btw, another idea is to actually split it into multiple contexts instead of a single one. That means each context can be updated in its own pace (or never). Check out the Informed library (kudos to @joepuzzo) for the inspiration. https://github.com/joepuzzo/informed/blob/3c4c3018f3985e85f9e1b23865a2326e0cb871bc/src/Context.js Notice also the |
@jaredpalmer I see checkbox handling in These are the unwrapped, dependent handlers I could find on master.
I think as opposed to using a
Initial proposal:
Open questions:
|
So it looks like this wasn't addressed in V2 at all. That's a shame, I was hoping to learn something new here. Oh well, it's unusable for me like this and I am expecting it is going to bite more people with Hooks adoption growing. |
@FredyC in my opinion one should always use the most exact dependencies for these React fns, to prevent extra re-renders regardless of the implementation. I think this is still a valid feature request, but even if it was implemented I'd recommend people use (The maintainers did not close this issue.) |
Yea, I did close it because I could not afford to wait for this and other fixes and had to write my own solution from the ground up based on MobX which is not only faster (only fields, not a whole form are re-rendered) but does not suffer from these issues because of stable references for anything.
It feels more like a workaround. Try to explain it to that ESLint rule which just sticks "formik" there when the auto-fix is enabled. Sure, you as a developer are responsible to handle deps correctly, but there is no clue for the user this is needed until an actual issue starts happening. And those can be pretty sneaky. |
I'd say that's more of a "react hooks" issue, than something specific to Formik. I've written up a proposal here which hopefully would help, but I can understand the inability to wait. |
🐛 Bug report / Feature request
Today, I cried...
Current Behavior
Consider the following contrived example. The ESLint rule
react/exhaustive-deps
immediately complains thatformik
needs to be in deps. Makes sense, why not? Ouch! Such callback will be recreated on every little change becauseuseFormikContext
always returns a new object.The callback alone wouldn't be too bad. But then comes
useEffect
into play and things get very bad. The ESLint will once again suggest adding callbacksetField
to deps. Originally the effect that is supposed to be executed once (on mount) is now executed on every little change.Lines of thinking here are like: "I have it wrapped in the callback, it's safe to have effect depend on it, right? Damn..."
Expected behavior
I am aware I can disable ESLint for that particular line and avoid adding that dependency there. That's not the point. Anyone can get burned by it because it's a good assumption it will work just fine.
Reproducible example
https://codesandbox.io/s/happy-dubinsky-91lhc?eslint=1&expanddevtools=1&module=%2Fsrc%2FFormMemory.jsx
Notice it grows geometrically for some reason and might kill your browser tab. But there is a button to actually start it, so don't worry to open and check the code first.
Suggested solution(s)
This is really tricky. One side of a problem is that recreating a new object will allow Context to re-render interested parties. With stable reference, no render would happen.
So I am thinking something along the lines of splitting state and api object and providing two hooks for accessing each. The api object can have a stable reference while state can still cause necessary re-render. And ESLint suggestions won't be a problem anymore.
The text was updated successfully, but these errors were encountered: