### 使用时机

当存在依赖全局状态或本地上下文的交互模块，且这些内容可能因导航事件而改变时，使用此功能可确保应用程序不同部分的一致性。

### `getServerState()` 与 `getServerContext()` 使用最佳实践

-   **只读引用：** `getServerState()` 和 `getServerContext()` 均返回只读对象。您可以使用这些对象来更新全局状态或本地上下文。
-   **回调集成：** 在存储[回调函数](/docs/reference-guides/interactivity-api/api-reference.md#accessing-data-in-callbacks)中集成这些函数，以响应状态和上下文的变化。`getServerState()` 和 `getServerContext()` 返回的都是响应式对象，这意味着它们的监听回调仅在属性值发生变化时触发。若属性值保持不变，则不会重新触发回调。

## 总结

请记住，有效状态管理的关键在于保持状态最小化并避免冗余。使用派生状态动态计算值，根据数据的作用域和需求在全局状态与本地上下文之间做出选择。这将有助于构建更清晰、更健壮的架构，使调试和维护更为轻松。最后，若需将状态或上下文与服务器同步，可通过 `getServerState()` 和 `getServerContext()` 实现这一目标。

### 示例：使用局部上下文实现独立状态的交互区块

此示例展示了一个交互区块，它显示计数器并支持递增操作。通过使用局部上下文，该区块的每个实例都将拥有独立的计数器，即使页面中添加了多个此类区块。

```php
<div
  data-wp-interactive="myCounterPlugin"
  <?php echo get_block_wrapper_attributes(); ?>
  data-wp-context='{ "counter": 0 }'
>
  <p>计数器：<span data-wp-text="context.counter"></span></p>
  <button data-wp-on-async--click="actions.increment">递增</button>
</div>
```

```js
store( 'myCounterPlugin', {
	actions: {
		increment() {
			const context = getContext();
			context.counter += 1;
		},
	},
} );
```

本示例说明：

1. 通过 `data-wp-context` 指令定义初始值为 `0` 的局部计数器上下文
2. 使用 `data-wp-text="context.counter"` 从局部上下文读取并显示计数器值
3. 递增按钮通过 `data-wp-on-async--click="actions.increment"` 触发递增操作
4. JavaScript 中的 `getContext` 函数用于访问和修改每个区块实例的局部上下文

用户可在页面中添加多个该区块实例，每个实例都将保持独立的计数器状态。点击某个区块的"递增"按钮仅影响该特定区块的计数器，不会对其他区块产生作用。

## 派生状态

Interactivity API 中的**派生状态**指根据全局状态或局部上下文的其他部分计算得出的值。该值按需计算而非直接存储，可确保一致性、减少冗余，并增强代码的声明性特性。

派生状态是现代状态管理的基础概念，并非 Interactivity API 独有。在其他主流状态管理系统中同样存在，例如 Redux 中称为“选择器”（selectors），Preact Signals 中称作“计算值”（computed values）。

派生状态具有以下核心优势，使其成为精心设计的应用状态中不可或缺的组成部分：

1. **单一数据源**：派生状态鼓励仅存储必要的原始数据，所有可基于核心数据计算的值都作为派生状态。这种方法可降低交互区块中出现数据不一致的风险。

2. **自动更新**：使用派生状态时，当基础数据发生变化，相关值会自动重新计算。这能确保交互区块的所有部分始终获取最新信息，无需人工干预。

3. **简化状态管理**：通过按需计算而非手动存储更新数值，可降低状态管理逻辑的复杂度，使代码更清晰、更易维护。

4. **提升性能**：多数情况下，派生状态可优化为仅在必要时重新计算，从而提升交互区块的性能表现。

5. **便于调试**：派生状态能更清晰地展现数据来源与转换过程，有助于快速定位交互区块中的问题。

本质上，派生状态允许以声明式方式表达交互区块中不同数据间的关联，而非在数据变化时强制更新相关值。

_请访问[响应式与声明式思维指南](/docs/reference-guides/interactivity-api/core-concepts/the-reactive-and-declarative-mindset.md)，深入了解如何在 Interactivity API 中运用声明式编码。_

在以下场景中建议使用派生状态：

-   当部分全局状态或局部上下文可从其他状态值计算得出时
-   需要避免手动保持同步的冗余数据时
-   通过自动更新派生值确保交互区块间的一致性时
-   通过消除更新多个关联状态属性的需求来简化操作时

## 订阅服务端状态与上下文

交互性API提供基于区域的路由功能，能够动态替换页面局部内容而无需整页刷新。当禁用"强制页面重载"开关时，[查询区块](/docs/reference-guides/core-blocks.md#query-loop)原生支持此功能。开发者可通过调用 [`@wordpress/interactivity-router`](https://github.com/WordPress/gutenberg/tree/trunk/packages/interactivity-router) 脚本模块中的 [`actions.navigate()`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-interactivity-router/#actions) 在自定义区块中实现相同功能。

使用基于区域的路由时，必须确保交互区块与服务端提供的全局状态和本地上下文保持同步。默认情况下，交互性API不会用服务端传值覆盖全局状态或本地上下文。该API提供两个函数来协助管理同步：[`getServerState()`](/docs/reference-guides/interactivity-api/api-reference.md#getserverstate) 和 [`getServerContext()`](/docs/reference-guides/interactivity-api/api-reference.md#getservercontext)。

### `getServerState()`

`getServerState()` 用于订阅**全局状态**在客户端导航期间发生的变化。此函数与 `getServerContext()` 类似，但作用于全局状态而非本地上下文。

`getServerState()` 返回一个只读的响应式对象。这意味着任何监视该返回对象的[回调函数](/docs/reference-guides/interactivity-api/api-reference.md#accessing-data-in-callbacks)仅会在函数返回值变更时触发。若值保持不变，回调不会重复触发。

以多题目测验为例：每个题目位于独立页面，当用户导航至新题目时，服务端将提供新题目及剩余答题时间。

```php
<div <?php echo wp_interactivity_state( 'myPlugin', array(
	'question' => get_question_for_page( get_the_ID() ),
	'timeLeft' => 5 * 60, // 回答所有题目的总剩余时间
) ); ?>>
```

```javascript
import { store, getServerState } from '@wordpress/interactivity';

store( 'myPlugin', {
	actions: {
		// 此操作通过指令触发，例如：
		// <button data-wp-on-click="actions.nextQuestion">下一题</button>
		*nextQuestion() {
			event.preventDefault( event );
			const { actions } = yield import(
				'@wordpress/interactivity-router'
			);
			actions.navigate( '/question-2' );
		},
	},
	callbacks: {
		// 此回调通过指令触发，例如：
		// <div data-wp-watch="callbacks.updateQuestion"></div>
		updateQuestion() {
			const serverState = getServerState();

			// 使用服务端的新值更新
			// 注意不更新`timeLeft`，因其表示所有题目的总剩余时间
			state.question = serverState.question;
		},
	},
} );
```

### `getServerContext()`

`getServerContext()` 用于订阅**本地上下文**在客户端导航期间发生的变化。此函数与 `getServerState()` 类似，但作用于本地上下文而非全局状态。

`getServerContext()` 返回一个只读的响应式对象。这意味着任何监视该返回对象的[回调函数](/docs/reference-guides/interactivity-api/api-reference.md#accessing-data-in-callbacks)仅会在函数返回值变更时触发。若值保持不变，回调不会重复触发。

以多题目测验为例：每个题目位于独立页面，当用户导航至新题目时，服务端将提供新题目及剩余答题时间。

```php
<div <?php echo wp_interactivity_data_wp_context( array(
	'currentQuestion' => get_question_for_page( get_the_ID() ),
), ); ?>>
```

```javascript
import { store, getServerContext } from '@wordpress/interactivity';

store( 'myPlugin', {
	actions: {
		// 此操作通过指令触发，例如：
		// <button data-wp-on-click="actions.nextQuestion">下一题</button>
		*nextQuestion() {
			event.preventDefault( event );
			const { actions } = yield import(
				'@wordpress/interactivity-router'
			);
			actions.navigate( '/question-2' );
		},
	},
	callbacks: {
		// 此回调通过指令触发，例如：
		// <div data-wp-watch="callbacks.updateQuestion"></div>
		updateQuestion() {
			const serverContext = getServerContext();
			const context = getContext();

			// 使用服务端的新值更新
			context.currentQuestion = serverContext.currentQuestion;
		},
	},
} );
```

### 示例：未使用派生状态 vs 使用派生状态

考虑一个需要显示计数器及其两倍数值的场景，我们对比两种实现方式：未使用派生状态与使用派生状态。

-   **未使用派生状态**

    ```js
    const { state } = store( 'myCounterPlugin', {
    	state: {
    		counter: 1,
    		double: 2,
    	},
    	actions: {
    		increment() {
    			state.counter += 1;
    			state.double = state.counter * 2;
    		},
    	},
    } );
    ```

    这种方式需要在 `increment` 操作中手动更新 `state.counter` 和 `state.double` 的值。虽然可行，但存在以下缺陷：

    -   声明性较弱
    -   当从多个位置更新 `state.counter` 时，若开发者忘记同步更新 `state.double` 可能导致错误
    -   需要额外关注相关值的更新，增加认知负担

-   **使用派生状态**

    ```js
    const { state } = store( 'myCounterPlugin', {
    	state: {
    		counter: 1,
    		get double() {
    			return state.counter * 2;
    		},
    	},
    	actions: {
    		increment() {
    			state.counter += 1;
    		},
    	},
    } );
    ```

    这个改进版本具有以下优势：

    -   `state.double` 被定义为获取器，自动从 `state.counter` 派生值
    -   `increment` 操作只需更新 `state.counter`
    -   无论 `state.counter` 在何时何地更新，`state.double` 总能保持正确值

### 示例：在本地上下文中使用派生状态

考虑一个初始化计数器的本地上下文场景：

```js
store( 'myCounterPlugin', {
	state: {
		get double() {
			const { counter } = getContext();
			return counter * 2;
		},
	},
	actions: {
		increment() {
			const context = getContext();
			context.counter += 1;
		},
	},
} );
```

```html
<div data-wp-interactive="myCounterPlugin">
	<!-- 这里将显示 "Double: 2" -->
	<div data-wp-context='{ "counter": 1 }'>
		两倍值：<span data-wp-text="state.double"></span>

		<!-- 此按钮将增加本地计数器 -->
		<button data-wp-on-async--click="actions.increment">递增</button>
	</div>

	<!-- 这里将显示 "Double: 4" -->
	<div data-wp-context='{ "counter": 2 }'>
		两倍值：<span data-wp-text="state.double"></span>

		<!-- 此按钮将增加本地计数器 -->
		<button data-wp-on-async--click="actions.increment">递增</button>
	</div>
</div>
```

在此示例中，派生状态 `state.double` 从每个元素所在的本地上下文读取数据，为每个使用实例返回正确的值。

### 示例：同时使用本地上下文和全局状态的派生状态

考虑一个包含全局税率和本地商品价格，并计算含税最终价格的场景：

```html
<div
	data-wp-interactive="myProductPlugin"
	data-wp-context='{ "priceWithoutTax": 100 }'
>
	<p>商品价格：$<span data-wp-text="context.priceWithoutTax"></span></p>
	<p>税率：<span data-wp-text="state.taxRatePercentage"></span></p>
	<p>含税价格：$<span data-wp-text="state.priceWithTax"></span></p>
</div>
```

```js
const { state } = store( 'myProductPlugin', {
	state: {
		taxRate: 0.21,
		get taxRatePercentage() {
			return `${ state.taxRate * 100 }%`;
		},
		get priceWithTax() {
			const { priceWithoutTax } = getContext();
			return priceWithoutTax * ( 1 + state.taxRate );
		},
	},
	actions: {
		updateTaxRate( event ) {
			// 更新全局税率
			state.taxRate = event.target.value;
		},
		updatePrice( event ) {
			// 更新本地商品价格
			const context = getContext();
			context.priceWithoutTax = event.target.value;
		},
	},
} );
```

在此示例中，`priceWithTax` 同时从全局 `taxRate` 和本地 `priceWithoutTax` 派生。当通过 `updateTaxRate` 或 `updatePrice` 操作更新全局状态或本地上下文时，交互性 API 会重新计算派生状态并更新 DOM 中必要的部分。

通过使用派生状态，您可以创建更易维护、更不易出错的代码库。这能确保相关状态值始终保持同步，降低操作逻辑的复杂度，使代码更具声明性且更易于理解。

### 使用派生状态

-   **初始化派生状态**

    通常，派生状态应使用 `wp_interactivity_state` 函数在服务器上进行初始化，其方式与全局状态完全相同。

    -   当初始值已知且为静态时，可以直接定义：

        ```php
        wp_interactivity_state( 'myCounterPlugin', array(
          'counter' => 1, // 这是全局状态。
          'double'  => 2, // 这是派生状态。
        ));
        ```

    -   或者可以通过进行必要的计算来定义：

        ```php
        $counter = 1;
        $double  = $counter * 2;

        wp_interactivity_state( 'myCounterPlugin', array(
          'counter' => $counter, // 这是全局状态。
          'double'  => $double,  // 这是派生状态。
        ));
        ```

    无论采用哪种方法，初始的派生状态值将在 PHP 渲染页面时使用，并且 HTML 将填充正确的值。

    _请访问 [服务端渲染指南](/docs/reference-guides/interactivity-api/core-concepts/server-side-rendering.md) 以了解更多关于指令在服务器上如何处理的信息。_

    即使派生状态属性依赖于本地上下文，同样的机制也适用。

    ```php
    <?php
    $counter = 1;

    // 这是本地上下文。
    $context = array( 'counter' => $counter );

    wp_interactivity_state( 'myCounterPlugin', array(
      'double' => $counter * 2, // 这是派生状态。
    ));
    ?>

    <div
      data-wp-interactive="myCounterPlugin"
      <?php echo wp_interactivity_data_wp_context( $context ); ?>
    >
      <div>
        计数器：<span data-wp-text="context.counter"></span>
      </div>
      <div>
        双倍：<span data-wp-text="state.double"></span>
      </div>
    </div>
    ```

    在 JavaScript 中，派生状态使用 getter 定义：

    ```js
    const { state } = store( 'myCounterPlugin', {
    	state: {
    		get double() {
    			return state.counter * 2;
    		},
    	},
    } );
    ```

    派生状态可以依赖于本地上下文，或者同时依赖于本地上下文和全局状态。

    ```js
    const { state } = store( 'myCounterPlugin', {
    	state: {
    		get double() {
    			const { counter } = getContext();
    			// 依赖于本地上下文。
    			return counter * 2;
    		},
    		get product() {
    			const { counter } = getContext();
    			// 依赖于本地上下文和全局状态。
    			return counter * state.factor;
    		},
    	},
    } );
    ```

    在某些情况下，当派生状态依赖于本地上下文，并且本地上下文在服务器上可以动态更改时，可以使用函数（闭包）动态计算派生状态，而不是使用初始派生状态。

    ```php
    <?php
    wp_interactivity_state( 'myProductPlugin', array(
      'list'    => array( 1, 2, 3 ),
      'factor'  => 3,
      'product' => function() {
        $state   = wp_interactivity_state();
        $context = wp_interactivity_get_context();
        return $context['item'] * $state['factor'];
      }
    ));
    ?>

    <template
      data-wp-interactive="myProductPlugin"
      data-wp-each="state.list"
    >
      <span data-wp-text="state.product"></span>
    </template>
    ```

    此 `data-wp-each` 模板将渲染以下 HTML（指令省略）：

    ```html
    <span>3</span>
    <span>6</span>
    <span>9</span>
    ```

-   **访问派生状态**

    在 HTML 标记中，派生状态的语法与全局状态的语法相同，只需在指令属性值中引用 `state`。

    ```html
    <span data-wp-text="state.double"></span>
    ```

    在 JavaScript 中也是如此。全局状态和派生状态都可以通过 store 的 `state` 属性使用：

    ```js
    const { state } = store( 'myCounterPlugin', {
    	// ...
    	actions: {
    		readValues() {
    			state.counter; // 常规状态，返回 1。
    			state.double; // 派生状态，返回 2。
    		},
    	},
    } );
    ```

    这种无区别的设计是有意的，允许开发者统一使用派生状态和全局状态，并使它们在实践中可以互换。

    你还可以从另一个派生状态访问派生状态，从而创建多级计算值。

    ```js
    const { state } = store( 'myPlugin', {
    	state: {
    		get double() {
    			return state.counter * 2;
    		},
    		get doublePlusOne() {
    			return state.double + 1;
    		},
    	},
    } );
    ```

-   **更新派生状态**

    派生状态不能直接更新。要更新其值，你需要更新该派生状态所依赖的全局状态或本地上下文。

    ```js
    const { state } = store( 'myCounterPlugin', {
    	// ...
    	actions: {
    		updateValues() {
    			state.counter; // 常规状态，返回 1。
    			state.double; // 派生状态，返回 2。

    			state.counter = 2;

    			state.counter; // 常规状态，返回 2。
    			state.double; // 派生状态，返回 4。
    		},
    	},
    } );
    ```

### 示例：使用全局状态通信的两个交互块

本示例包含两个独立的交互块：一个用于显示计数器，另一个包含递增计数器的按钮。这些块可以放置在页面任意位置，无需遵循特定的HTML结构。也就是说，一个块不必作为另一个块的内嵌块存在。

-   **计数器块**

    ```php
    <?php
    wp_interactivity_state( 'myCounterPlugin', array(
      'counter' => 0
    ));
    ?>

    <div
      data-wp-interactive="myCounterPlugin"
      <?php echo get_block_wrapper_attributes(); ?>
    >
      计数器：<span data-wp-text="state.counter"></span>
    </div>
    ```

-   **递增块**

    ```php
    <div
      data-wp-interactive="myCounterPlugin"
      <?php echo get_block_wrapper_attributes(); ?>
    >
      <button data-wp-on-async--click="actions.increment">
        递增
      </button>
    </div>
    ```

    ```js
    const { state } = store( 'myCounterPlugin', {
    	actions: {
    		increment() {
    			state.counter += 1;
    		},
    	},
    } );
    ```

本示例说明：

1.  通过服务端的 `wp_interactivity_state` 初始化全局状态，设置计数器初始值为0
2.  计数器块使用 `data-wp-text="state.counter"` 读取全局状态并显示当前计数值
3.  递增块包含的按钮通过 `data-wp-on-async--click="actions.increment"` 在点击时触发递增操作
4.  JavaScript中的 `increment` 操作通过递增 `state.counter` 直接修改全局状态

这两个块相互独立，可置于页面任意位置，无需在DOM结构中形成嵌套或直接关联。页面中可以添加多个此类交互块实例，它们将共享并更新同一全局计数值。

## 本地上下文

Interactivity API中的**本地上下文**特指在HTML结构特定元素内定义的局部数据。与全局状态不同，本地上下文仅可在定义元素及其子元素中访问。

本地上下文在以下场景中特别有用：
-   需要为多个交互块实例维护独立状态
-   需要封装仅与特定交互块及其子元素相关的数据
-   需要实现仅限于界面特定区域的隔离功能

### 本地上下文操作指南

-   **初始化本地上下文**

    通过 `data-wp-context` 指令直接在HTML结构中初始化本地上下文，该指令接收定义上下文初始值的JSON字符串：

    ```html
    <div data-wp-context='{ "counter": 0 }'>
    	<!-- 子元素可访问 `context.counter` -->
    </div>
    ```

    也可使用 `wp_interactivity_data_wp_context` PHP辅助函数在服务端初始化，确保字符串化值的正确转义和格式化：

    ```php
    <?php
    $context = array( 'counter' => 0 );
    ?>

    <div <?php echo wp_interactivity_data_wp_context( $context ); ?>>
      <!-- 子元素可访问 `context.counter` -->
    </div>
    ```

-   **访问本地上下文**

    在HTML标记中，可通过指令值直接引用 `context` 访问本地上下文值：

    ```html
    <div data-wp-bind--hidden="!context.isOpen">
    	<span data-wp-text="context.counter"></span>
    </div>
    ```

    在JavaScript中，可使用 `getContext` 函数访问本地上下文值：

    ```js
    store( 'myPlugin', {
    	actions: {
    		sendAnalyticsEvent() {
    			const { counter } = getContext();
    			myAnalyticsLibrary.sendEvent( 'updated counter', counter );
    		},
    	},
    	callbacks: {
    		logCounter() {
    			const { counter } = getContext();
    			console.log( `当前计数值：${ counter }` );
    		},
    	},
    } );
    ```

    `getContext` 函数返回触发操作/回调执行的元素对应的本地上下文。

-   **更新本地上下文**

    在JavaScript中可通过修改 `getContext` 返回的对象来更新本地上下文值：

    ```js
    store( 'myPlugin', {
    	actions: {
    		increment() {
    			const context = getContext();
    			context.counter += 1;
    		},
    		updateName( event ) {
    			const context = getContext();
    			context.name = event.target.value;
    		},
    	},
    } );
    ```

    对本地上下文的修改将自动触发依赖该值的所有指令更新。

    _请参阅[响应式与声明式思维](/docs/reference-guides/interactivity-api/core-concepts/the-reactive-and-declarative-mindset.md)指南，深入了解Interactivity API中的响应式工作原理。_

-   **嵌套本地上下文**

    本地上下文支持嵌套结构，子上下文可继承并覆盖父上下文的值：

    ```html
    <div data-wp-context='{ "theme": "light", "counter": 0 }'>
    	<p>主题：<span data-wp-text="context.theme"></span></p>
    	<p>计数器：<span data-wp-text="context.counter"></span></p>

    	<div data-wp-context='{ "theme": "dark" }'>
    		<p>主题：<span data-wp-text="context.theme"></span></p>
    		<p>计数器：<span data-wp-text="context.counter"></span></p>
    	</div>
    </div>
    ```

    此示例中，内层 `div` 将使用 `"dark"` 作为主题值，同时继承父上下文的计数器值 `0`。

# 理解全局状态、局部上下文与派生状态

Interactivity API 为创建交互式区块提供了强大的框架。要充分发挥其能力，关键在于理解何时使用全局状态、局部上下文或派生状态。本指南将阐明这些概念，并通过实际示例帮助您做出合适的选择。

首先简要定义全局状态、局部上下文和派生状态：

-   **全局状态：** 页面中任何交互式区块均可访问和修改的全局数据，确保不同区块间保持同步。
-   **局部上下文：** 在 HTML 结构特定元素内定义的局部数据，仅该元素及其子元素可访问，为独立区块提供专属状态。
-   **派生状态：** 基于全局状态或局部上下文动态计算的数值，按需生成确保数据一致性，避免存储冗余数据。

接下来我们将深入探讨每个概念，并提供详细示例。

## 全局状态

Interactivity API 中的**全局状态**是指页面中任何交互式区块均可访问和修改的全局数据。它作为共享信息枢纽，使区块的不同部分能够通信并保持同步。无论交互式区块在 DOM 树中的位置如何，全局状态都是实现它们之间信息交换的理想机制。

在以下场景中应使用全局状态：

-   需要在 DOM 层级中无直接关联的多个交互式区块间共享数据
-   希望为所有交互式区块维护统一数据源
-   处理同时影响多个界面元素的数据
-   需要实现页面级全局功能

### 全局状态操作指南

-   **初始化全局状态**

    通常应使用 `wp_interactivity_state` 函数在服务端定义初始全局状态值：

    ```php
    // 填充初始全局状态值
    wp_interactivity_state( 'myPlugin', array(
      'isDarkTheme' => true,
      'show'        => false,
      'helloText'   => __( 'world' ),
    ));
    ```

    这些初始全局状态值将在 PHP 渲染页面时用于填充发送至浏览器的 HTML 标记。

    -   开发者在 PHP 文件中编写的 HTML 标记：

        ```html
        <div
        	data-wp-interactive="myPlugin"
        	data-wp-class--is-dark-theme="state.isDarkTheme"
        	class="my-plugin"
        >
        	<div data-wp-bind--hidden="!state.show">
        		Hello <span data-wp-text="state.helloText"></span>
        	</div>
        	<button data-wp-on-async--click="actions.toggle">切换</button>
        </div>
        ```

    -   指令处理完成后准备发送至浏览器的 HTML 标记：

        ```html
        <div
        	data-wp-interactive="myPlugin"
        	data-wp-class--is-dark-theme="state.isDarkTheme"
        	class="my-plugin is-dark-theme"
        >
        	<div hidden data-wp-bind--hidden="!state.show">
        		Hello <span data-wp-text="state.helloText">world</span>
        	</div>
        	<button data-wp-on-async--click="actions.toggle">切换</button>
        </div>
        ```

    _请访问[服务端渲染指南](/docs/reference-guides/interactivity-api/core-concepts/server-side-rendering.md)了解指令在服务端处理的详细信息。_

    若全局状态未在 PHP 页面渲染过程中使用，也可直接在客户端定义：

    ```js
    const { state } = store( 'myPlugin', {
    	state: {
    		isLoading: false,
    	},
    	actions: {
    		*loadSomething() {
    			state.isLoading = true;
    			// ...
    		},
    	},
    } );
    ```

    _请注意，虽然这种方式可行，但通常建议在服务端定义所有全局状态。_

-   **访问全局状态**

    在 HTML 标记中，可通过在指令属性值中引用 `state` 直接访问全局状态值：

    ```html
    <div data-wp-bind--hidden="!state.show">
    	<span data-wp-text="state.helloText"></span>
    </div>
    ```

    在 JavaScript 中，`@wordpress/interactivity` 包提供的 `store` 函数兼具设置器和获取器功能，返回指定命名空间的存储对象。

    要在操作和回调中访问全局状态，可使用 `store` 函数返回对象的 `state` 属性：

    ```js
    const myPluginStore = store( 'myPlugin' );

    myPluginStore.state; // 这是 'myPlugin' 命名空间的状态
    ```

    也可对 `store` 返回的对象进行解构：

    ```js
    const { state } = store( 'myPlugin' );
    ```

    即使在定义存储时也可采用相同方式，这是最常见的使用场景：

    ```js
    const { state } = store( 'myPlugin', {
    	state: {
    		// ...
    	},
    	actions: {
    		toggle() {
    			state.show = ! state.show;
    		},
    	},
    } );
    ```

    使用 `wp_interactivity_state` 函数在服务端初始化的全局状态也会自动包含在该对象中，因为它会从服务端自动序列化到客户端：

    ```php
    wp_interactivity_state( 'myPlugin', array(
      'someValue' => 1,
    ));
    ```

    ```js
    const { state } = store( 'myPlugin', {
    	state: {
    		otherValue: 2,
    	},
    	actions: {
    		readGlobalState() {
    			state.someValue; // 存在且初始值为 1
    			state.otherValue; // 存在且初始值为 2
    		},
    	},
    } );
    ```

    最后，所有对同一命名空间的 `store` 函数调用都会合并：

    ```js
    store( 'myPlugin', { state: { someValue: 1 } } );

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

    /* 所有 `store` 调用都返回同一对象的稳定引用，
     * 因此可从任意调用中获取 `state` 引用 */
    const { state } = store( 'myPlugin' );

    store( 'myPlugin', {
    	actions: {
    		readValues() {
    			state.someValue; // 存在且初始值为 1
    			state.otherValue; // 存在且初始值为 2
    		},
    	},
    } );
    ```

-   **更新全局状态**

    要更新全局状态，只需在从 `store` 函数获取 `state` 对象后对其进行修改：

    ```js
    const { state } = store( 'myPlugin', {
    	actions: {
    		updateValues() {
    			state.someValue = 3;
    			state.otherValue = 4;
    		},
    	},
    } );
    ```

    对全局状态的更改将自动触发依赖修改值的所有指令更新。

    _请访问[响应式与声明式思维指南](/docs/reference-guides/interactivity-api/core-concepts/the-reactive-and-declarative-mindset.md)了解 Interactivity API 中响应式工作原理的详细信息。_