前言
之前章节了解到在 Astro 中引用不同框架的组件非常容易,但这些组件的状态如何管理?让我们进入全局状态管理的世界。
在不同组件之间传递状态
在一些 UI 框架中会提供创建 context 的方式来管理状态,但由于 Astro 采用「局部 Hydration」的方式来渲染页面,因此无法做到。
因此 Astro 推荐的解方是:Nano Stores。
为什么选择 Nano Stores?
- 它很小(不到 1 KB)。
- 与框架无关,可用于整合不同框架组件之间的状态。
什么?又要学一个新的框架?根据我简单的体验,它与其他状态管理并没有太大差异,只需要对 JavaScript 有基础的了解就能很快上手。以下是一个小示例,展示如何在 Vue 与 React 之间传递和管理状态。
计数器小示例
定义问题
目前有两个计数器组件: CounterVue.vue 与 CounterReact.jsx 希望通过导入 Nano Stores 让这两个组件之间的状态可以互通。
第一步:安装对应套件
npx astro add reactnpx astro add vuenpm install nanostores @nanostores/reactnpm install nanostores @nanostores/vue第一步:创建 Store
创建一个 stores 文件夹并且添加 counter.js 文件,透过 atom 这个函数的帮助,我们能将状态记录于其中并且导出以在其他组件中引用。
import { atom } from 'nanostores';
const counter = atom({ value: 1 });const increaseCounter = () => counter.set({ value: counter.get().value + 1 });const decreaseCounter = () => { counter.set({ value: counter.get().value - 1 });};
export { counter, increaseCounter, decreaseCounter };第二步:撰写个别元件
import { useStore } from '@nanostores/react';import { counter, increaseCounter, decreaseCounter } from '../stores/counter';
export default function CounterReact() { const count = useStore(counter);
return ( <div style={{ border: '1px solid blue' }}> <button onClick={decreaseCounter}>-</button> <div>{count.value}</div> <button onClick={increaseCounter}>+</button> <p>React Component</p> </div> );}<script setup>import { useStore } from '@nanostores/vue';import { counter, increaseCounter, decreaseCounter } from '../stores/counter';
const count = useStore(counter);</script>
<template> <div style="border: 1px solid green"> <button @click="decreaseCounter">-</button> <div>{{ count.value }}</div> <button @click="increaseCounter">+</button> <p>Vue Component</p> </div></template>第三步:引入元件
---import CounterReact from '../components/CounterReact';import CounterVue from '../components/CounterVue.vue';---
<div class="container"> <CounterReact client:load /> <CounterVue client:load /></div>
<style> .container { display: flex; padding: 2rem; gap: 1rem; }</style>
这样一来两种不同框架的状态与方法也能很好地配合在一起。
其他替代方案?
可以考虑一些“简单”的方法,比如通过「自定义浏览器事件」让组件之间彼此沟通,或是依赖各框架提供的解决方案:
总结
今天的示例展示了在 Astro 中如何处理不同框架间的状态。在以静态内容为主的网站中,通常也较少需要写到复杂的客户端状态管理,很高兴有套件可以简单整合这件事情。
延伸阅读
- Share State Between Islands - Astro 文档
- The easiest way to handle app state - Awesome
- Simpler ReactJS global state Nano Stores - bholmesdev
- Day11 - 全局状态管理 - 相同文章同步发布于 iThome 铁人赛中