diff --git a/js/src/components/adaptive-form/adaptive-form.js b/js/src/components/adaptive-form/adaptive-form.js
index 7e72248acc..9194fd43af 100644
--- a/js/src/components/adaptive-form/adaptive-form.js
+++ b/js/src/components/adaptive-form/adaptive-form.js
@@ -196,12 +196,12 @@ function AdaptiveForm( { onSubmit, extendAdapter, children, ...props }, ref ) {
// Related to WC 6.9. Only one delegate can be consumed at a time in this render prop to
// ensure the updating states will always be the latest when calling.
if ( batchQueue.length ) {
- // Use `setImmediate` to avoid the warning of request state updates while rendering.
+ // Use `setTimeout` to avoid the warning of request state updates while rendering.
// Mutating a React hook state is an anti-pattern in most cases. Here is done intentionally
// because it's necessary to ensure this component will be triggered re-rendering through
// `setBatchQueue`, but also to avoid calling `setBatchQueue` here and triggering additional
// rendering again.
- setImmediate( () => setDelegation( batchQueue.shift() ) );
+ setTimeout( () => setDelegation( batchQueue.shift() ) );
}
/* === Start of enhancement-related codes === */
diff --git a/js/src/components/adaptive-form/adaptive-form.test.js b/js/src/components/adaptive-form/adaptive-form.test.js
index 3b343535c6..7c2b9a1eea 100644
--- a/js/src/components/adaptive-form/adaptive-form.test.js
+++ b/js/src/components/adaptive-form/adaptive-form.test.js
@@ -196,4 +196,113 @@ describe( 'AdaptiveForm', () => {
expect( inspect ).toHaveBeenLastCalledWith( false, 0 );
} );
+
+ describe( 'Compatibility patches', () => {
+ it( 'Should update all changes to values for the synchronous multiple calls to `setValue`', async () => {
+ render(
+
+ { ( { setValue, values } ) => {
+ return (
+ <>
+
+ );
+
+ const article = screen.getByRole( 'article' );
+
+ expect( article.textContent ).toBe( 'Foo Bar (empty)' );
+
+ await act( async () => {
+ await userEvent.click( screen.getByRole( 'button' ) );
+ jest.runAllTimers();
+ } );
+
+ expect( article.textContent ).toBe( 'Hey Howdy hi[at]greetings' );
+ } );
+
+ it( 'Should call back to `onChange` for the changed value only', async () => {
+ const onChange = jest.fn();
+
+ render(
+
+ { ( { setValue, getInputProps } ) => {
+ return (
+ <>
+
+ );
+
+ await act( async () => {
+ await userEvent.click( screen.getByRole( 'button' ) );
+ jest.runAllTimers();
+ } );
+
+ expect( onChange ).toHaveBeenCalledTimes( 1 );
+ expect( onChange ).toHaveBeenLastCalledWith(
+ { name: 'firstName', value: 'Hey' },
+ expect.any( Object ),
+ true
+ );
+
+ await userEvent.type( screen.getByRole( 'textbox' ), 'a' );
+
+ expect( onChange ).toHaveBeenCalledTimes( 2 );
+ expect( onChange ).toHaveBeenLastCalledWith(
+ { name: 'lastName', value: 'a' },
+ expect.any( Object ),
+ true
+ );
+
+ await userEvent.click( screen.getByRole( 'checkbox' ) );
+
+ expect( onChange ).toHaveBeenCalledTimes( 3 );
+ expect( onChange ).toHaveBeenLastCalledWith(
+ { name: 'agreedTerms', value: true },
+ expect.any( Object ),
+ true
+ );
+ } );
+ } );
} );
diff --git a/js/src/hooks/useCroppedImageSelector/useCroppedImageSelector.js b/js/src/hooks/useCroppedImageSelector/useCroppedImageSelector.js
index 478f3a9475..f3623709ac 100644
--- a/js/src/hooks/useCroppedImageSelector/useCroppedImageSelector.js
+++ b/js/src/hooks/useCroppedImageSelector/useCroppedImageSelector.js
@@ -315,7 +315,7 @@ export default function useCroppedImageSelector( {
// since `toolbar` will be triggered the refresh event at the end, so this function
// must be called after that.
if ( this === frame ) {
- setImmediate( handleSelectionToggle );
+ setTimeout( handleSelectionToggle );
return;
}