-
Notifications
You must be signed in to change notification settings - Fork 2.4k
fix(ui): nested fields disappear when manipulating rows in form state #11906
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
Conversation
New approach: remove Right now, we need How to determine if the field needs to be renderedRight now, we omit the We will try and add a new prop called:
This way, we only need to check that certain fields have New steps for when building a field state:
The above flow appears to allow us to completely remove the Work to do prior to implementing this new approach:
Branch: https://github.com/payloadcms/payload/tree/fix/component-field-state |
🚀 This is included in version v3.32.0 |
…payloadcms#11906) Continuation of payloadcms#11867. When rendering custom fields nested within arrays or blocks, such as the Lexical rich text editor which is treated as a custom field, these fields will sometimes disappear when form state requests are invoked sequentially. This is especially reproducible on slow networks. This is different from the previous PR in that this issue is caused by adding _rows_ back-to-back, whereas the previous issue was caused when adding a single row followed by a change to another field. Here's a screen recording demonstrating the issue: https://github.com/user-attachments/assets/5ecfa9ec-b747-49ed-8618-df282e64519d The problem is that `requiresRender` is never sent in the form state request for row 2. This is because the [task queue](payloadcms#11579) processes tasks within a single `useEffect`. This forces React to batch the results of these tasks into a single rendering cycle. So if request 1 sets state that request 2 relies on, request 2 will never use that state since they'll execute within the same lifecycle. Here's a play-by-play of the current behavior: 1. The "add row" event is dispatched a. This sets `requiresRender: true` in form state 1. A form state request is sent with `requiresRender: true` 1. While that request is processing, another "add row" event is dispatched a. This sets `requiresRender: true` in form state b. This adds a form state request into the queue 1. The initial form state request finishes a. This sets `requiresRender: false` in form state 1. The next form state request that was queued up in 3b is sent with `requiresRender: false` a. THIS IS EXPECTED, BUT SHOULD ACTUALLY BE `true`!! To fix this this, we need to ensure that the `requiresRender` property is persisted into the second request instead of overridden. To do this, we can add a new `serverPropsToIgnore` to form state which is read when the processing results from the server. So if `requiresRender` exists in `serverPropsToIgnore`, we do not merge it. This works because we actually mutate form state in between requests. So request 2 can read the results from request 1 without going through an additional rendering cycle. Here's a play-by-play of the fix: 1. The "add row" event is dispatched a. This sets `requiresRender: true` in form state b. This adds a task in the queue to mutate form state with `requiresRender: true` 1. A form state request is sent with `requiresRender: true` 1. While that request is processing, another "add row" event is dispatched a. This sets `requiresRender: true` in form state AND `serverPropsToIgnore: [ "requiresRender" ]` c. This adds a form state request into the queue 1. The initial form state request finishes a. This returns `requiresRender: false` from the form state endpoint BUT IS IGNORED 1. The next form state request that was queued up in 3c is sent with `requiresRender: true`
Continuation of #11867. When rendering custom fields nested within arrays or blocks, such as the Lexical rich text editor which is treated as a custom field, these fields will sometimes disappear when form state requests are invoked sequentially. This is especially reproducible on slow networks.
This is different from the previous PR in that this issue is caused by adding rows back-to-back, whereas the previous issue was caused when adding a single row followed by a change to another field.
Here's a screen recording demonstrating the issue:
pr-11906.mp4
The problem is that
requiresRender
is never sent in the form state request for row 2. This is because the task queue processes tasks within a singleuseEffect
. This forces React to batch the results of these tasks into a single rendering cycle. So if request 1 sets state that request 2 relies on, request 2 will never use that state since they'll execute within the same lifecycle.Here's a play-by-play of the current behavior:
a. This sets
requiresRender: true
in form staterequiresRender: true
a. This sets
requiresRender: true
in form stateb. This adds a form state request into the queue
a. This sets
requiresRender: false
in form staterequiresRender: false
a. THIS IS EXPECTED, BUT SHOULD ACTUALLY BE
true
!!To fix this this, we need to ensure that the
requiresRender
property is persisted into the second request instead of overridden. To do this, we can add a newserverPropsToIgnore
to form state which is read when the processing results from the server. So ifrequiresRender
exists inserverPropsToIgnore
, we do not merge it. This works because we actually mutate form state in between requests. So request 2 can read the results from request 1 without going through an additional rendering cycle.Here's a play-by-play of the fix:
a. This sets
requiresRender: true
in form stateb. This adds a task in the queue to mutate form state with
requiresRender: true
requiresRender: true
a. This sets
requiresRender: true
in form state ANDserverPropsToIgnore: [ "requiresRender" ]
c. This adds a form state request into the queue
a. This returns
requiresRender: false
from the form state endpoint BUT IS IGNOREDrequiresRender: true