群岛间的状态共享
当使用群岛结构 / 部分激活构建一个 Astro 网站时,你可能会遇到这样的问题:我想在我的组件之间共享状态。
像 React 或者 Vue 这样的 UI 框架可能鼓励使用 “context” 来为其他组件提供上下文信息。但是在 Astro 或者 Markdown 中的 部分激活组件 (partially hydrating components) 不能使用上下文封装。
Astro 推荐了一个不同的客户端共享存储的解决方案: Nano Stores。

为什么使用 Nano Stores?
段落标题 为什么使用 Nano Stores?Nano Stores 库允许你编写任何组件都能与之互动的状态库。我们推荐 Nano Stores,因为:
- 它是轻量级的。 Nano Stores 提供了你所需要的最低限度的 JS(不到 1KB),并且零依赖。
- 它是框架无关的。 这意味着在框架之间共享状态将是无缝的!Astro 是建立在灵活性之上的,所以我们喜欢那些无论你的偏好如何都能提供类似开发者体验的解决方案。
尽管如此,你仍然可以探索一些替代方案。这些方法包括:
- Svelte 的内置 stores
- Solid signals 组件之外的上下文
- Vue 的响应式 API
- 在组件之间 发送自定义浏览器事件
🙋 我可以在 .astro
文件中或者其他服务端组件使用 Nano Stores 吗?
Nano Stores 可以在 <script>
标签中使用,以在 .astro
组件之间共享状态。然而,不推荐在服务端组件的 frontmatter 中使用 Nano Stores,原因如下:
- 从一个
.astro
文件或者 非激活组件 写入状态库将不会影响 客户端组件 值的获取。 - 你不能将 Nano Store 作为一个 “prop” 传递给客户端组件。
- 你不能从一个
.astro
文件中订阅状态库变化,因为 Astro 组件不会重新渲染。
如果你理解了这些限制,并且找到了一个使用场景,你可以尝试一下 Nano Stores! 请记住,Nano Stores 是为了响应客户端的变化而构建的。
🙋 Svelte stores 和 Nano Stores 相比如何?
Nano Stores 和 Svelte stores 十分相似! 事实上, Nano Stores 允许你使用与 Svelte Store 相同的 $
方式 来订阅。
如果你想避免使用第三方库, Svelte stores 本身就是一个很棒的跨组件通信库。不过,你可能喜欢使用 Nano Stores 如果: a)你喜欢他们的插件 “objects” 和 async state。 b)你想要在 Svelte 和其他 UI 框架如 Preact 或者 Vue 之间进行通信。
🙋 Solid signals 和 Nano Stores 相比如何?
如果你已经使用 Solid 有一段时间了,你可能试着将 signals 或者 stores 移出你的组件。这是一个很棒的方式来在 Solid islands 之间共享状态!尝试从一个共享的文件中导出 signals:
import { createSignal } from 'solid-js';
export const sharedCount = createSignal(0);
所有导入了 sharedCount
的组件都会共享共同的状态。虽然这很好用,但是你可能更喜欢 Nano Stores 如果:
a)你喜欢他们的插件 “objects” 和 async state。
b)你想要在 Svelte 和其他 UI 框架如 Preact 或者 Vue 之间进行通信。
安装 Nano Stores
段落标题 安装 Nano Stores为你喜欢的 UI 框架安装 Nano Stores 和他们的帮助包:
npm i nanostores @nanostores/preact
npm i nanostores @nanostores/react
npm i nanostores @nanostores/solid
npm i nanostores
这里不需要安装帮助包!因为 Nano Stores 可以像标准的 Svelte 状态库一样被使用。
npm i nanostores @nanostores/vue
你可以跳转到 Nano Stores 使用指南 或者跟随我们下面的例子!
用例 - 电商购物车抽屉
段落标题 用例 - 电商购物车抽屉假如我们正在搭建一个简单的电商页面,有下面三个交互元素:
- 一个 “add to cart” 按钮
- 一个购物车抽屉来显示已添加的商品
- 一个购物车抽屉开关
在你的机器上尝试完整的例子 或者通过 StackBlitz 在线尝试!
你基础的 Astro 文件看起来应该是这样的:
---import CartFlyoutToggle from '../components/CartFlyoutToggle';import CartFlyout from '../components/CartFlyout';import AddToCartForm from '../components/AddToCartForm';---
<!DOCTYPE html><html lang="en"><head>...</head><body> <header> <nav> <a href="/">Astro storefront</a> <CartFlyoutToggle client:load /> </nav> </header> <main> <AddToCartForm client:load> <!-- ... --> </AddToCartForm> </main> <CartFlyout client:load /></body></html>