Astro Islands 與 React 組件集成實踐
Astro架構
Astro 的 Islands 架構允許在靜態 HTML 中嵌入交互式的 React 組件,同時保持頁面整體的零 JS 默認輸出。本文記錄在 monorepo 環境下集成共享 React 組件的實踐心得。
什麼是 Astro Islands
Astro 默認生成純靜態 HTML,只有顯式加上 client:* 指令的組件才會水合為交互式 Island。這意味著大多數頁面組件(佈局、靜態卡片、Prose 容器)完全不需要 JS。
<!-- 靜態渲染,零 JS -->
<Card title="靜態卡片" href="/blog" />
<!-- 啟用水合,包含事件監聽器 -->
<Card client:load tilt title="交互卡片" href="/blog" />
在 pnpm Monorepo 中共享組件
在 packages/ui 中定義 React 組件,各 app 通過 @personal/ui 包名引入:
import { Card } from '@personal/ui/components/Card.tsx';
import { Nav } from '@personal/ui/components/Nav.tsx';
關鍵點:@personal/ui 不需要 build 步驟,直接暴露 .tsx 源文件,由各 app 的 Vite 統一編譯。tsconfig 中 "noEmit": true 確保包本身不輸出編譯產物。
client 指令選擇
| 指令 | 時機 | 適用場景 |
|---|---|---|
client:load | 頁面加載立即水合 | 首屏可見的交互組件(Nav) |
client:visible | 進入視口時水合 | 列表中的卡片、圖表 |
client:idle | 瀏覽器空閒時水合 | 非關鍵交互(搜索框) |
常見陷阱
問題: 在 Astro 中使用帶 useState 的組件但沒加 client:*,導致事件無響應。
解決: 靜態渲染時 React hooks 不執行,必須加 client 指令。
問題: 服務端/客戶端 hydration 不一致警告。
解決: 確保組件的初始渲染不依賴 window 或 document,通過 useEffect 延遲訪問瀏覽器 API。