Make WordPress Core

Opened 5 months ago

Closed 3 months ago

Last modified 3 months ago

#63898 closed defect (bug) (fixed)

Add support for lazy-loaded derived state props

Reported by: darerodz's profile darerodz Owned by: luisherranz's profile luisherranz
Milestone: 6.9 Priority: normal
Severity: normal Version: 6.9
Component: Interactivity API Keywords: has-patch has-unit-tests
Focuses: Cc:

Description

There is a problem with derived state props when the store containing them is not loaded before hydration, which can happen with stores loaded asynchronously, e.g., @wordpress/interactivity-router, and also they have a PHP equivalent used for server-side rendering.

In that case, when those missing derived state props are evaluated, they will return undefined, and the directives subscribed to that value will replace the value generated on the server with the PHP function with undefined, effectively removing the HTML generated on the server.

The Interactivity API should be aware of which values were generated on the server via a PHP Closure (derived state props) and avoid replacing the directive's value on the client until a getter is available that can correctly recalculate it.

This requires serializing which state props are closures that were used during directive processing to generate the HTML markup.

Change History (9)

This ticket was mentioned in PR #9673 on WordPress/wordpress-develop by @darerodz.


5 months ago
#1

  • Keywords has-patch has-unit-tests added

This PR handles the server-side part to add support for "lazy" derived state props. From the trac ticket description:

There is a problem with derived state props when the store containing them is not loaded before hydration, which can happen with stores loaded asynchronously, e.g., @wordpress/interactivity-router, and also they have a PHP equivalent used for server-side rendering.

In that case, when those missing derived state props are evaluated, they will return undefined, and the directives subscribed to that value will replace the value generated on the server with the PHP function with undefined, effectively removing the HTML generated on the server.

The Interactivity API should be aware of which values were generated on the server via a PHP Closure (derived state props) and avoid replacing the directive's value on the client until a getter is available that can correctly recalculate it.

The way it works is by informing the iAPI runtime which Closures have been evaluated on the server, and serializing their paths into a data structure that is serialized along with the initial state and configuration.

There's also a special case with the data-wp-each-child directive. I should know if the corresponding parent data-wp-each directive is using a derived state prop to render the list.

Trac ticket: https://core.trac.wordpress.org/ticket/63898

Related Gutenberg issue: https://github.com/WordPress/gutenberg/issues/70872
Related Gutenberg PR: https://github.com/WordPress/gutenberg/pull/71125

@darerodz commented on PR #9673:


3 months ago
#3

My only thought is if maybe we should rename derivedStatePropsAccessed to derivedStateClosures so it's more explicit that it is related to closures only?

Naming is hard. 😅

We can agree that using the term "derived state" is fine, as we use it extensively in the documentation. Regarding "props accessed" vs. "closures", maybe the "closure" part is implicit already in "derived state"? Only those properties are defined using closures. And I added the term "accessed" to indicate that these derived state props were accessed during server-side processing.

I know the term is a bit long, and I don't mind changing it to derivedStateClosures. Just sharing my reasoning. 😄

@luisherranz commented on PR #9673:


3 months ago
#4

My thinking is that not all derived state needs to be tracked, only the derived state that is defined as closures in the server. There's derived state that is still "accessed" but it's value in the server is static.

@darerodz commented on PR #9673:


3 months ago
#5

My thinking is that not all derived state needs to be tracked, only the derived state that is defined as closures in the server. There's derived state that is still "accessed" but it's value in the server is static.

Makes sense. I just changed the name to derivedStateClosures. @luisherranz, feel free to commit the changes!

@luisherranz commented on PR #9673:


3 months ago
#6

Can you change the $this->derived_state_props_accessed property to $this->derived_state_closures as well?

#7 @luisherranz
3 months ago

  • Owner set to luisherranz
  • Resolution set to fixed
  • Status changed from new to closed

In 60953:

Interactivity API: Support lazy-loaded derived state props.

Serialize on the server the paths of derived state closures accessed during directive processing and include them in the serialized data. During the Interactivity API hydration, if a directive reads one of those paths before its JavaScript getter is available, keep the server-rendered value intact instead of replacing it with undefined.

props darerodz.
Fixes #63898.

#9 @sabernhardt
3 months ago

  • Milestone changed from Awaiting Review to 6.9
Note: See TracTickets for help on using tickets.