iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0

https://ithelp.ithome.com.tw/upload/images/20230926/20141551fg32Bm67sd.jpg

前言

前面章節了解到在 Astro 中引用不同框架的元件是極其容易的事情,但這些元件中的狀態要怎麼去管理呢?讓我們進入全域狀態管理的世界。

在不同組件之間傳遞狀態

在一些 UI 框架中會提供創建 context 的方式來管理狀態,但由於 Astro 採用「局部 Hydration」的方式來渲染頁面,因此無法辦到。

因此 Astro 推薦的解方是:Nano Stores

為什麼是 Nano Stores?

  • 它很小(1 KB 不到)。
  • 與框架無關,可以用它來整合各元件各框架之間的狀態。

什麼?又一個新的框架要學?就我簡單體驗與其他狀態管理並沒有太大的差異,只需要對 JavaScript 有基礎的了解很快就能上手,以下是一個小範例展示如何在 Vue 與 React 之間傳遞管理狀態。

計數器小範例

定義問題

目前有兩個計數器元件: CounterVue.vueCounterReact.jsx 希望藉由導入 Nano Stores 讓這兩個元件之間的狀態可以互通。

第一步:安裝對應套件

npx astro add react
npx astro add vue 
npm install nanostores @nanostores/react
npm install nanostores @nanostores/vue

第一步:創建 Store

創建一個 stores 資料夾並且添加 counter.js 檔案,透過 atom 這個函式的幫助,我們能將狀態紀錄於其中並且輸出並在其他元件中引用。

// counter.js
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 };

第二步:撰寫個別元件

// CounterReact.jsx
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>
  );
}
// CounterVue.vue
<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>

第三步:引入元件

// index.astro
---
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>

https://ithelp.ithome.com.tw/upload/images/20230926/20141551KquHtc43N7.png

如此一來兩個不同框架的狀態與方法也能很好的配合在一起。

其他替代方案?

可以考慮一些「簡單」的方法,向是透過「客製化瀏覽器事件」讓元件之間彼此溝通,或是依賴各框架提供的解方:

總結

今天的範例展示了 Astro 中是如何處理不同框架間的狀態。在寫靜態內容為主的網站時,通常也比較少機會會需要寫到太複雜的客戶端狀態管理,很高興有套件可以簡單整合這件事情。

延伸閱讀

(目前 iT 邦不支援 Astro 語法的高光 😅,因此歡迎到我的部落格閱讀本系列相關文章,正同步更新中!)


上一篇
Day10 -整合 UI 框架
下一篇
Day12 - 基礎路由
系列文
網頁開發沒有這麼簡單過!實際案例帶你上手 Astro.js30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言