-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Prerequisites
- I have read the documentation
What theme are you using?
mui
What is your question?
I'm attempting to add UI/components that modify form state directly.
Making the whole form 'controlled' (in the React sense) by a wrapping component, ie by tying RJSF Form formData
and onChange
to React.useState
, seems to mostly work. The form data can be modified in the wrapper component via the state setter and responds mostly how I'd like. However, I've run into problems with array field key stability. I'll get into details of that below, but it might be an XY problem if there's a better way to take control of form data:
- Is this kind of 'controlled' RJSF form an intended/supported use case?
- (The docs seem to imply that the
formData
prop toForm
is only to set default/initial data; perhaps using it this way is a stretch?) - (edit: yes, controlled rjsf forms are supported, per comment below from heath-freenome)
- (The docs seem to imply that the
- Are there any preferred alternatives?
- (I've considered using an
ArrayField
custom field and going through itsonChange
; but this still runs into the key stability issue; going through the array items themselves wouldn't allow eg an append)
- (I've considered using an
The array key stability problem:
Assuming the controlled form setup above, when the form data is updated by calling the state setter (from React.useState
), it clobbers the stable key
s that the ArrayField
sets up internally, ie the ones implemented in #1335 to fix #1046 . As a result they get reset on re-render, and open the door to symptoms that #1335 hoped to prevent (edit: actually, this probably (?) only causes extra re-renders; at the moment there are no known issues caused by this - if anyone discovers an issue caused by this please link this issue or comment/re-open).
As a concrete example of what can break: a custom (edit: this was a red herring, and likely actually an integration issue between react 19 and ArrayFieldTemplate
with item add/remove animations via react-transition-group
might key the transitions off the array item key; when the keys get clobbered, the next array item add animates as if all items (including existing ones) are being newly added.react-transition-group
)
A work-around?
A (very fragile) work-around is to pass a key remapper function down through eg formContext
and having a custom ArrayField
field/template call it on re-render, and use the remapped keys as the actual array item keys:
interface FormContext {
arrayKeyMapper?: (arrayId: string, index: number, key: string) => string
}
That function then has to do a bit of a dance to map "new" internal keys to the old/stable ones, coordinated to any "clobbering" form data change. It might use the indices to do this, but has to be very careful to use those indices 'safely' relative to the actual form data change operation. This... works... but it is a lot of complexity and fragility.
Is there a cleaner way to accomplish this?
Thank you very much for the library, and for your help!