Vue - 元件規劃心得

簡介

閱讀patterns.dev內Vue元件相關的設計模式文章,做個筆記記錄一下

Container / Presentational Pattern

  • 其中一種分類原則,就是可以分為ContainerPresentational兩個種類
  • 將UI設計和邏輯分離,加強維護性,例如當我想改變按鈕樣式時,不會去影響應用邏輯

1. Presentational Components

  • 重點在於外觀展示
  • 不涉及資料修改
  • 透過props接收資料

2. Container Components

  • 處理功能邏輯,例如:串接API取得資料
  • 或是從Pinia / Vuex這類的全局狀態管理取得資料
  • 使用props傳入資料給Presentational Components

範例:顯示Pokemon卡片

  1. 創建展示元件:PokeCard.vue
<script setup>const { pokemon } = defineProps({  pokemon: {    type: Array,    default: () => []  }})</script><template>  <ul>    <li v-for="poke in pokemon" :key="poke.id">      <p>{{ poke.name }}</p>      <img :src="poke.sprites.front_default" :alt="poke.name" />    </li>  </ul></template>
  1. 創建Container元件:PokeContainer.vue
<script setup>  import { ref, onMounted } from "vue";  const pokemon = ref([])  onMounted(async () => {    const response = await fetch('https://pokeapi.co/api/v2/pokemon/ditto')    const data = await response.json()    pokemon.value.push(data)})</script><template>  <PokeCard :pokemon="pokemon" /></template>
  • Demo

    Container 元件

    取得API資料放入UI元件

    UI-展示元件

    我是誰?

有什麼優點

  1. 職責清晰分離: 通過將UI和業務邏輯分開,提高程式碼的組織性和可維護性
  2. 提高重用性和測試便利: 展示元件易於重用和測試,由於它們不包含複雜的業務邏輯
  3. 簡化狀態管理: 容器元件集中處理狀態和邏輯,減少跨元件的狀態傳遞和混亂

Vue3 Composition API的影響

  • 開始模糊容器與呈現元件之間的界限
  • 提供更靈活的方式來組織元件和邏輯

Composables

  1. 允許封裝和重用狀態和邏輯
  2. 同樣可以達到UI畫面和商業邏輯分開處理的目的
  3. 就不需要另外寫Container元件

使用Composable改寫:

  1. 創建/composables/usePokemonInfos.js
import { ref, onMounted } from 'vue'export default function usePokemonInfos() {  const pokemon = ref([])  onMounted(async () => {    try {      const response = await fetch('https://pokeapi.co/api/v2/pokemon/ditto')      const data = await response.json()      pokemon.value.push(data)  } catch (error) {      console.error(error)  }  })  return { pokemon }}
  1. PokeCard.vue從composables取得資料
<script setup>  import usePokemonInfos from "../composables/usePokemonInfos";  const { pokemon } = usePokemonInfos();</script><template>  <ul>    <li v-for="poke in pokemon" :key="poke.id">      <p>{{ poke.name }}</p>      <img :src="poke.sprites.front_default" :alt="poke.name" />    </li>  </ul></template>

實際應用心得

先前在火箭隊的畢業專題中,使用Nuxt3開發,便有嘗試過Container元件的設計方式,雖然需要更多的時間去規劃,但結構確實較為清晰單純。

後來發現,若該頁面的內容不會太複雜,直接在Nuxt的pages / Vue的views頁面檔案中,使用composables取得API資料後,渲染UI畫面,會更為簡便快速,例如文章頁面內只會有文章相關的API資料,就可以直接在頁面發送API請求,再用props傳入UI元件。

如果較為複雜,例如首頁有許多不同種類的內容,再利用Container元件來分區塊,根據需求狀況不同,來選擇最適合的開發模式。

參考資料

# Vue