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

iAPI Docs: Understanding global state, local context and derived state #63930

Conversation

luisherranz
Copy link
Member

What?

Following up on The Reactive and Declarative Mindset guide, this is the second guide of the new Core Concepts section of the Interactivity API, focusing on explaining the concept of state and the different types of state (global, local, and derived) used in the Interactivity API.

Why?

The Interactivity API would benefit from some guides that explain the concepts and mental models, not just from the API references.

How?

For now, I have simply added the guide as a markdown file.

The work to generate the new Core Concepts section is in the pull request for the guide for reactive and declarative mindset. So, once that pull request is merged, we can change this one to fit that format.

@luisherranz luisherranz added [Type] Developer Documentation Documentation for developers [Feature] Interactivity API API to add frontend interactivity to blocks. labels Jul 25, 2024
@luisherranz luisherranz self-assigned this Jul 25, 2024
@SantosGuillamot
Copy link
Contributor

After a first read, the guide looks amazing! 👏 I think these are key concepts to understand while using the Interactivity API and this pull request does a great job explaining them. I might be biased because I was already familiar with the terms, but I like how it is structured. I feel the explanations including "When to use X" and the different examples are really useful.

I'll try to take a deeper look once you consider it ready.

Copy link
Member

@gziolo gziolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to see this type of guide added as it will help to onboard developers. Thank you so much for working on it 👏🏻

It sounds like a good direction with the nomenclature of global state vs local context. I did the first pass with the focus on the global state and left my feedback inline. I intend to have a look at local context next, but I might have other priorities in the next days so feel free to proceed based on feedback from other contributors 😄

One thing that isn't fully clear from this guide is what are the best practices for calling wp_interactivity_state. Where devs should locate the code call, inside the main plugin file vs inside the render_callback of the block type, and what are the implications of that. That might apply to store() calls as well, when I think about it now, too.


### When to use global state

- You need to share data between multiple blocks that are not directly related in the DOM hierarchy.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One crucial aspect that is important to clarify is the nuances of how developers should handle multiple blocks of the same type, e.g., several Image blocks rendered on the page, in contrast to how that would look like in the case where two different block types would like to share the same global state, ex. the Gallery block and the Image block set as the child, or the Navigation block and some completely custom block type that would interact with it from a completely random place on the page.


```html
<span
data-wp-bind--hidden="!state.shown"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For education purposes, will this magically read the value from the myPlugin namespace if there is no wp-data-interactivy="myPlugin" set higher in the HTML tree?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we can add data-wp-interactive to make it clearer, thanks!

The global state initialized on the server using the `wp_interactivity_state` function is also included in that object:

```php
wp_interactivity_state( 'myPlugin', array(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it intentional to reuse the same namespace myPlugin as in the first example for declaring server state? Later the docs state:

Lastly, all calls to the store function with the same namespace are merged together:

In effect, I was wondering if at this moment I should assume that the store contains:

  • counter, shown, example - wp_interactivity_state firs call
  • isLoading - store first call
  • someValue - wp_interactivity_state second call
  • otherValue - store second call

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's not very clear. I'll think it over about the example in this guide. Thanks!


store( 'myPlugin', { state: { otherValue: 2 } } );

// All calls to `store` return a stable reference (the same object).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the same object in this context? It would help to clarify it further.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll try to improve it, thanks!


```php
<?php
wp_interactivity_state( 'myPlugin', array(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's getting confusing to see the same namespace myPlugin referenced again. What would be the recommendation for plugin authors when picking the namespace name? Should they use one for their plugin, split by block types?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to create a specific guide that explains namespaces and scope.

Comment on lines +411 to +414
wp_interactivity_state( 'myPlugin', array(
'counter' => 1, // This is global state.
'double' => 2, // This is derived state.
));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What alternatives are there to explain the idea of a derived state with the first example presented? I often saw something similar to the following:

Suggested change
wp_interactivity_state( 'myPlugin', array(
'counter' => 1, // This is global state.
'double' => 2, // This is derived state.
));
$counter = 1;
wp_interactivity_state( 'myPlugin', array(
'counter' => $counter, // This is global state.
'double' => 2 * $counter, // This is derived state.
));

When placing the value, it isn't immediately clear that double is computed from other entries in the state.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion. I will apply it to the guide. Thank you!

Copy link
Contributor

@jffng jffng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general this helped my understanding of global state, local context, and derived state. I was able to clean up the store of something I'm working on and feel more confident in the implementation, after reading this guide.


- **Initializing the derived state**

Typically, the derived state should be initialized on the server using the `wp_interactivity_state` function in the exact same way as the global state:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why typically? Because you often depend on values from the server (e.g. block attributes) to calculate the initial values of state?

Copy link
Member Author

@luisherranz luisherranz Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have created a specific guide to explain server-side rendering and how directives are processed on the server. It's part of this PR:

Hopefully, it will answer your question.

(Feedback welcomed on that guide too 😄)

</div>
```

In the client, the derived state is defined using getters:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, this is the key difference between derived vs global state, and could be presented much earlier in the guide. That could just be how I learn though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I'll take a look to see if it can be mentioned earlier. Thanks, Jeff!

@luisherranz
Copy link
Member Author

I am closing this pull request in favor of this one where I have merged this guide with the other two initial guides:

@luisherranz luisherranz closed this Aug 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Interactivity API API to add frontend interactivity to blocks. [Type] Developer Documentation Documentation for developers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants