Describe the bug
The watch
method does not recognize the updates from useFieldArray
. In the codesandbox i am console logging all watched values out. Any changes from the form field values should be reflected in that watch method, including the modified values in useFieldArray
but in this case the values are not accurate.
To Reproduce
Steps to reproduce the behavior:
append
delete twice
Object {test: Array[3]}
(it should be a length of 2)append
again.Codesandbox link (Required)
https://codesandbox.io/s/issue-usefieldarray-watch-broken-kph9x
Expected behavior
When fields are modified from useFieldArray
, the watch
method should reflect the same modified array. This way we are able to get the subscribe to the values externally for our needs.
Desktop (please complete the following information):
Additional context
The reason we need this to work is for using the watch method combined with useEffect
to dispatch changes to a context provider so the user can see a _live update_ of their form. In our case, we don't want to manually setup onChange events for every field but watch/subscribe to all fields and update our context so we can display the live information elsewhere.
Try watch that array field : watch('test')
thanks for report this issue: https://codesandbox.io/s/issue-usefieldarray-watch-broken-m5x4h patch is coming.
@bluebill1049 Amazing turn around time! Did you happen to notice, though, that if you remove _all_ of the instances it snaps back to the initial values instead of an empty array?
Yea, that's expected behaviour for watch
. I do see your concern tho. you may need to use formState like touched/dirty to counter with this issue.
Hmm... I can see how we'd check to see if the field is/dirty touched to know if it's been modified, but I'm not sure how that would help. If the field has been dirty but is back to its default state, we can't assume that means it's empty. Would you mind elaborating a bit more on your idea?
In my mind there's a fundamental difference between the initial state of a field and its watched state. I would think that watch only returns the default value until the field is dirty, at which point it returns whatever its actual state is. In what scenario would it make sense for a field to appear default in a dirty state?
yea @JasonTheAdams, i agree with your statement above. The reason behind such behaviour is so when user invoke watch
the first time will not return undefined
since none of the inputs have been registered.
Let me do some investigation, see if we can improve this behaviour, worse case i will add a description in the doc and provide alternative solution with formState.
Awesome! Thank you!
@bluebill1049 This issue still persists in v5.3.1
I'm not sure what happened because you had the issue fixed in your patch.
Here is the codesandbox:
https://codesandbox.io/s/issue-usefieldarray-watch-broken-v531-bwovf
justWatchedValue
is undefined & allWatchedValue
is not right eitherstrangle... I will take a look at it.
Much appreciated! useFieldArray
is our last roadblock to refactor fully into RHF from Final Form. Everything else is working great! 馃檶
I found the issue: reason behind
automation saved my a** last weekend... also this fix should be correct now. I may have to release a beta version for you guys to unblock you. I am bit hesitated to release stuff during the weekdays (due to my job if something goes wrong, i wouldn't be able to fix)
Hahah! The dark side of automation. 馃槅
I'd be fine with a beta since it's specifically for this issue (which we greatly appreciate). We can then immediately report back on this and hopefully bump up to the next stable release next week.
thanks for understanding @JasonTheAdams 馃檹
So just to make sure we're on the same page, @bluebill1049, we should expect to see a beta release some point soon?
I will release a beta once the build pass.
Oh and after my breakfast 馃ぃ
Perfect! 馃嵆 馃崬 馃
here you go: 5.3.2-beta.1
Much appreciated!
Thank you for helping us with this @bluebill1049 !
After testing out the beta version It seems we're 90% there but unfortunately some more issues arise. I'll explain what's happening and maybe you can help answer some questions.
updated sandbox: https://codesandbox.io/s/issue-usefieldarray-watch-broken-v532-beta1-bwovf?file=/src/App.js
The original issue here is technically fixed (watch method and values form useFieldArray are in sync) except anytime you remove an item from the field array the watch value deletes the entire field array key from the watch values before returning the correct value. This causes some issues for us because we are syncing those watched values to our context and there will be a blink in render of those values because they disappear before appearing again.
It seems something happened to formState dirtyFields and touched because they stay empty and false when interacting with the form.
When you watch all fields watch()
does the amount of fields cause the amount re-renders?
Something that final form has that works really nice is called Form Spy. We have been trying to mimick this behavior using this approach:
const allWatchedValues = watch({nest: true}, initialValues);
const allWatchedPreviousValues = usePrevious(allWatchedValues);
const allWatchedValuesIsEqual = isEqual(allWatchedValues, allWatchedPreviousValues);
useEffect(() => {
if (onChange && allWatchedValues) {
onChange(allWatchedValues);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [allWatchedValuesIsEqual]);
I'm wondering what you think about adding a way to do this in RHF. some things that may work are adding an onChange
callback param to watch()
or creating something new like subscription(values, onChange)
.
Interested in hearing your thoughts on this.
Thanks!
Thanks for the detailed report:
RHF is uncontrolled (normal form should be) even with useFieldArray
, because of that If you are watching the entire Field Array, you basically treat it as controlled. so we will need to send an extra re-render to update e the watch returned value (only applied to Field Array, because field gets to add and remove), this is expected.
I will need to see a codesandbox, if there is bug around, we will fix it.
I would not recommend watch(), i think i have stated that in the doc. it's basically trigger re-render on each key stroke like controlled.
I will read into it, thanks :)
Thanks for the reply!
okay I understand, but i'm confused on why the entire array key disappears when removing an item from the array because this doesn't happen when you append. also those values are stored in default values so re-render shouldn't affect the array key at all. It seems like there is an issue with the remove()
method.
https://codesandbox.io/s/issue-usefieldarray-watch-broken-v532-beta1-bwovf?file=/src/App.js
Yes, that's we want it for. We are building many live preview forms so while the user is typing they will see the value being live updated elsewhere. So, we are using watch()
to listen for all form input onChange events to send those values to our react context wrapper.
thanks!
Let's take a look 1, 2 tmr.
Hi @bluebill1049!
Just wanted to chime in and make our use-case completely clear so you're not throwing darts in a dark room.
Our team is coming to the end of building a platform which has Campaigns which map to various web pages. We have a live-preview builder where the user can change settings for their Campaign and watch the affects live. To do this we are watching for values to change in the form and then are passing the values up to a Context which is used by the previewer. As such, it's important to us that we're able to know _when_ values change and dispatch the new values.
We're keeping track of our dependencies on the project and are budgeting that, post release, we'll be able to financially support our dependencies on a regular basis, as well as contribute ourselves. So we're hoping to partner with RHF long-term and have a great on-going relationship where we show our support and appreciation with our open-source partners.
If there's any more context we can provide to help clear up our use-case, please feel free to ask any questions.
Thanks @JasonTheAdams for the detailed explanation.
2: dirtyFields
is working as expected
useFieldArray
touched formState is not refreshing the form; looks like touched is working as well :
Issue 2 is working at my end, maybe i miss the step to reproduce. let me know how did you produce the issue.
Issue 1: needs more time to investigate, will spend sometimes today over the lunch break or tonight.
I can successfully reproduce issue 1: creating a seperate issue for this.
useFieldArray with remove action return empty array
codesandbox:
https://codesandbox.io/s/issue-usefieldarray-watch-broken-v532-beta1-bwovf?file=/src/App.js
steps:
Thanks for the fast response @bluebill1049 you rock!
Re: Issue 2. I was thinking formState touched & dirtyFields would change if you interact with the field array - maybe that's not the case?
No worries @jonwaldstein
Issues 2: i used your code example and it's working for me, take a look the screenshots as well.
@bluebill1049
Re: Issue 2
Okay I see that when you click or type into any items in the field array it will trigger touched/dirtyFields and add the array items individually to the dirtyFields set. Although formState.dirty
will become true if you use any of the field array buttons without clicking or typing into the inputs (this is what I was expecting with dirtyFields too).
When a user clicks any of the fieldArray buttons like append
and remove
it should add the field array key to dirtyFields - that way we would know if that field array as a whole is dirty since it's also making the formState.dirty
true. Since those dirtyFields are a set
i wonder if you can just add the key to the set when its dirty and then continue to add the array items like this: ['test', 'test[1]', 'test[2]']
than you could search for your array key like formState.dirtyFields.has('test')
when needed.
touched
: i believe is corrected behaviour, this should only set to true when user blue the inputdirtyFields
: I am not 100% sold on the idea.changes the value, turning the control dirty
Do you have any good reference to back that behaviour dirtyFields
?
RE: dirtyFields
Okay I don't want to get too off track with this because it's not the main issue and I know you're working hard on fixes, but I would like you to think about the relationship between formState.dirty
and formState.dirtyFields
with me.
If formState.dirty
becomes true shouldn't formState.dirtyFields
show you _what_ is dirty?
This relationship can be summed up by asking two questions (codesandbox below):
console.log("[is form state dirty?]", formState.dirty);
console.log("[if yes what fields are dirty?]", [...formState.dirtyFields]);
You see, when I click a button in field array the formState.dirty
becomes true
. Except dirtyFields
never tells me what specifically is dirty
.
https://codesandbox.io/s/issue-dirtyfields-v532-beta1-6w2y8?file=/src/App.js
RE:
dirtyFields
Okay I don't want to get too off track with this because it's not the main issue and I know you're working hard on fixes, but I would like you to think about the relationship between
formState.dirty
andformState.dirtyFields
with me.If
formState.dirty
becomes true shouldn'tformState.dirtyFields
show you _what_ is dirty?This relationship can be summed up by asking two questions (codesandbox below):
console.log("[is form state dirty?]", formState.dirty); console.log("[if yes what fields are dirty?]", [...formState.dirtyFields]);
You see, when I click a button in field array the
formState.dirty
becomestrue
. ExceptdirtyFields
never tells me what specifically isdirty
.https://codesandbox.io/s/issue-dirtyfields-v532-beta1-6w2y8?file=/src/App.js
That's a valid point for dirtyFields. 馃I think you are right here, will fix this behaviour.
Touched fields not getting updated when user append/prepend item
Okay I don't want to get too off track with this because it's not the main issue and I know you're working hard on fixes, but I would like you to think about the relationship between formState.dirty and formState.dirtyFields with me.
If formState.dirty becomes true shouldn't formState.dirtyFields show you what is dirty?
This relationship can be summed up by asking two questions (codesandbox below):
console.log("[is form state dirty?]", formState.dirty);
console.log("[if yes what fields are dirty?]", [...formState.dirtyFields]);
You see, when I click a button in field array the formState.dirty becomes true. Except dirtyFields never tells me what specifically is dirty.
https://codesandbox.io/s/issue-dirtyfields-v532-beta1-6w2y8?file=/src/App.js
closing this issue, all issues have been distributed into seperate issue tickets to track and fix.
Thanks @bluebill1049 馃檶
@bluebill1049 unfortunately have to re-open this issue along with something going on with reset()
:
Please visit the codesandbox below:
https://codesandbox.io/s/issue-rhf-values-v541-f7ye2?file=/src/App.js
In v5.3.1 we were able to use reset(values)
on submit to reset the form state with the new values. As you can see from this example, there appears to be a problem with the functionality of using reset(values)
. Please let me know if you need anymore details. Thanks!
looks like someone else reported this issue as well.
let's track it there: https://github.com/react-hook-form/react-hook-form/issues/1404 cause it's more specific.
Thanks a lot for the detailed issue report as well.
Most helpful comment
Hi @bluebill1049!
Just wanted to chime in and make our use-case completely clear so you're not throwing darts in a dark room.
Our team is coming to the end of building a platform which has Campaigns which map to various web pages. We have a live-preview builder where the user can change settings for their Campaign and watch the affects live. To do this we are watching for values to change in the form and then are passing the values up to a Context which is used by the previewer. As such, it's important to us that we're able to know _when_ values change and dispatch the new values.
We're keeping track of our dependencies on the project and are budgeting that, post release, we'll be able to financially support our dependencies on a regular basis, as well as contribute ourselves. So we're hoping to partner with RHF long-term and have a great on-going relationship where we show our support and appreciation with our open-source partners.
If there's any more context we can provide to help clear up our use-case, please feel free to ask any questions.