Skip to content
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

fix(ui): nested fields disappear when queued in form state #11867

Merged
merged 2 commits into from
Mar 26, 2025

Conversation

jacobsfletch
Copy link
Member

@jacobsfletch jacobsfletch commented Mar 25, 2025

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.

Here's a screen recording demonstrating the issue:

pr-11867.mp4

The problem is that form state invocations are placed into a task queue which aborts the currently running tasks when a new one arrives. By doing this, local form state is never dispatched, and the second task in the queue becomes stale.

The fix is to not abort the currently running task. This will trigger a complete rendering cycle, and when the second task is invoked, local state will be up to date.

Fixes #11340, #11425, and #11824.

Related: #11906.

@jacobsfletch jacobsfletch changed the title fix(ui): sequentially queued form state tasks cause custom components to disappear fix(ui): nested custom components sometimes disappear when queued in form state Mar 25, 2025
@jacobsfletch jacobsfletch merged commit 10ac989 into main Mar 26, 2025
78 checks passed
@jacobsfletch jacobsfletch deleted the fix/form-state-queues branch March 26, 2025 00:40
@jacobsfletch jacobsfletch changed the title fix(ui): nested custom components sometimes disappear when queued in form state fix(ui): nested fields disappear when queued in form state Mar 28, 2025
kendelljoseph pushed a commit that referenced this pull request Mar 31, 2025
…form state (#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 because form state invocations are placed into a [task
queue](#11579) which aborts
the currently running tasks when a new one arrives. By doing this, local
form state is never dispatched, and the second task in the queue becomes
stale.

The fix is to _not_ abort the currently running task. This will trigger
a complete rendering cycle, and when the second task is invoked, local
state will be up to date.

Fixes #11340, #11425, and #11824.
jmikrut pushed a commit that referenced this pull request Apr 1, 2025
…#11906)

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:


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](#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`
Copy link
Contributor

github-actions bot commented Apr 1, 2025

🚀 This is included in version v3.32.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RichText Input field keeps disappearing from admin panel DOM (for custom block) ?
2 participants