From f4b013f830d526f6d361627dd73642ac6931d8a0 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 6 Nov 2024 06:44:29 -0800 Subject: [PATCH] Delay block hydration to allow stores to initialize (#66772) Co-authored-by: westonruter Co-authored-by: michalczaplinski Co-authored-by: annezazu Co-authored-by: artemiomorales Co-authored-by: cbravobernal Co-authored-by: t-hamano --- packages/interactivity/src/init.ts | 11 +++++++++++ packages/interactivity/src/utils.ts | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/interactivity/src/init.ts b/packages/interactivity/src/init.ts index ddf6785d4dfdf..fa1eec51c3e27 100644 --- a/packages/interactivity/src/init.ts +++ b/packages/interactivity/src/init.ts @@ -33,6 +33,17 @@ export const init = async () => { `[data-${ directivePrefix }-interactive]` ); + /* + * This `await` with setTimeout is required to apparently ensure that the interactive blocks have their stores + * fully initialized prior to hydrating the blocks. If this is not present, then an error occurs, for example: + * > view.js:46 Uncaught (in promise) ReferenceError: Cannot access 'state' before initialization + * This occurs when splitTask() is implemented with scheduler.yield() as opposed to setTimeout(), as with the former + * split tasks are added to the front of the task queue whereas with the latter they are added to the end of the queue. + */ + await new Promise( ( resolve ) => { + setTimeout( resolve, 0 ); + } ); + for ( const node of nodes ) { if ( ! hydratedIslands.has( node ) ) { await splitTask(); diff --git a/packages/interactivity/src/utils.ts b/packages/interactivity/src/utils.ts index 9cd6f8bebb0d1..ab6b0074727ee 100644 --- a/packages/interactivity/src/utils.ts +++ b/packages/interactivity/src/utils.ts @@ -54,7 +54,7 @@ const afterNextFrame = ( callback: () => void ) => { /** * Returns a promise that resolves after yielding to main. * - * @return Promise + * @return Promise */ export const splitTask = typeof window.scheduler?.yield === 'function'