iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
1
Modern Web

玩轉 Storybook系列 第 19

玩轉 Storybook: Day 19 Wire in data - Vue & Vuex

Container and Presentational

官網的程式碼架構,會把元件分成二種類型-容器型(Container)及表現型(Presentational),因此可以做到更好的關注點分離,讓元件架構可以易於的被重複使用。

表現型的特性

  • 關注元件如何呈現,會有大部分的DOM Markup 及 樣式設定
  • 只用 props 來承載接收資料,不會有資料相關的操作,不會有狀態
  • Storybook及測試會用此版本的元件

容器型的特性

  • 關注元件的功能邏輯
  • 會有狀態,會有資料相關的操作
  • 頁面上實際是用此版本的元件

更多詳細說明請看此 BLOG

把 TaskList 拆分成以上表現型及容器型

新增 Vuex

$ npm add vuex

或是使用 vue ui 新增 vuex

安裝完成後,會增加 store/index.js 在資料夾中

這樣 Vuex 就加裝完成了,可以把 Task 的資料邏輯移至 Store 中

// src/store.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    tasks: [
      { id: '1', title: 'Something', state: 'TASK_INBOX' },
      { id: '2', title: 'Something more', state: 'TASK_INBOX' },
      { id: '3', title: 'Something else', state: 'TASK_INBOX' },
      { id: '4', title: 'Something again', state: 'TASK_INBOX' },
    ],
  },
  mutations: {
    ARCHIVE_TASK(state, id) {
      state.tasks.find(task => task.id === id).state = 'TASK_ARCHIVED';
    },
    PIN_TASK(state, id) {
      state.tasks.find(task => task.id === id).state = 'TASK_PINNED';
    },
  },
  actions: {
    archiveTask({ commit }, id) {
      commit('ARCHIVE_TASK', id);
    },
    pinTask({ commit }, id) {
      commit('PIN_TASK', id);
    },
  },
});

元件組裝架構

表現型 PureTaskList.vue

原來的TaskList.vue 修改成為 PureTaskList.vue (表現型),裡面的程式碼結構只專注於呈現,使用 props 接收資料

<!--src/components/PureTaskList.vue-->
<template>
<!--same content as before-->
</template>

<script>
import Task from "./Task";
export default {
  name: "pure-task-list",
  ...
}

容器型 TaskList.vue

TaskList.vue (容器型) 使用 PureTaskList.vue (表現型),再加上 Vuex 做資料與狀態操作。

<!--src/components/TaskList.vue`-->
<template>
  <div>
    <pure-task-list :tasks="tasks" @archive-task="archiveTask" @pin-task="pinTask" />
  </div>
</template>

<script>
  import PureTaskList from './PureTaskList';
  import { mapState, mapActions } from 'vuex';

  export default {
    name: 'task-list',
    components: {
      PureTaskList,
    },
    methods: {
      ...mapActions(['archiveTask', 'pinTask']),
    },
    computed: {
      ...mapState(['tasks']),
    },
  };
</script>

頁面呈現 App.vue

App.vue 使用 TaskList.vue (容器型)

<!--src/App.vue-->
<template>
  <div id="app">
    <task-list />
  </div>
</template>

<script>
  import store from './store';
  import TaskList from './components/TaskList.vue';

  export default {
    name: 'app',
    store,
    components: {
      TaskList,
    },
  };
</script>
<style>
  @import "./assets/index.css";
</style>

修改 Stories 使用 表現型元件

把 TaskList 分成 容器型 (TaskList.vue) 及 表現型(PureTaskList.vue),會更容易去測試。

Stories 只專注於 UI 呈現的效果,所以我們要把 TaskList.stories.js 改為 PureTaskList.stories.js,並調整程式碼如下圖所示。

修改 單元測試 使用 表現型元件

小結

本篇修改的程式碼:https://git.io/JUyyS

Next

完成了更複雜的元件結構分類,我們可以繼續把元件向上組裝成頁面。

Reference

Wire in data - Vue

Presentational and Container Components


上一篇
玩轉 Storybook: Day 18 Automated Visual Testing
下一篇
玩轉 Storybook: Day 20 Construct a screen - Vue
系列文
玩轉 Storybook30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言