點燈坊

失くすものさえない今が強くなるチャンスよ

使用 Module 抽出 JavaScript 重複部分

Sam Xiao's Avatar 2021-08-27

對於重複 HTML 部分,我們可抽出 Component;對於重複 JavaScript 部分,我們可抽出 Module。

Version

Vue 3.2

Page

overview000

以最經典的 counter 來看看 Vue 3 如何抽出重複 JavaScript。

App.vue

<template>
  <button @click='onClick'>+</button> {{ count }}
</template>

<script setup>
let count = $ref (0)

let onClick = _ => count++
</script>

假設 count state 與 onClick 為 JavaScript 重複部分。

Module

overview000

功能不變,但抽出共用 module。

useCounter.js

import { ref } from 'vue'

export default _ => {
  let count = ref (0)
  
  let onClick = _ => count.value++

  return {
    count,
    onClick
  }
}

第 3 行

export default _ => {

  return {
    
  }
}

Module 基本上架構如下:

  • 以 default export 宣告 anonymous function
  • 最後以 return object 形式方便 destructure

其實這就是 JavaScript 著名的 Module Pattern,它使用 Closure 讓每個 component 有自己的 state

第 4 行

let count = ref (0)
  
let onClick = _ => count.value++

將原本 component 內重複的 JavaScript 複製貼上。

Vue 3.2 目前 $ref 只能用在 SFC,還無法用在 module 內

第 8 行

return {
  count,
  onClick
}

將要給 component 使用的 state 與 function 回傳。

因為可能建立不少 state 與小 function 內部使用,可藉由 Module Pattern 將 state 與 function 封裝在 module 內

App.vue

<template>
  <button @click='onClick'>+</button> {{ count }}
</template>

<script setup>
import useCounter from '/src/modules/useCounter'

let { count, onClick } = useCounter ()
</script>

第 7 行

import useCounter from '/src/modules/useCounter'

useCounter module 引用 useCounter

第 9 行

let { count, onClick } = useCounter ()

執行 useCounter,並從回傳 Object 解構出 count state 與 onClick

Component

module001

同時使用兩個 <MyCounter> component,可發現 count state 各自爲政,不會互相影響。

MyCounter.vue

<template>
  <button @click='onClick'>+</button>
  <span>{{ count }}</span>
</template>

<script setup>
import useCounter from '/src/modules/useCounter'

let { count, onClick } = useCounter ()
</script>

建立 MyCounter component,其內的 count state 與 onClick 都來自於 useCounter module。

App.vue

<template>
  <MyCounter/>
  <MyCounter/>
</template>

<script setup>
import MyCounter from '/src/components/MyCounter.vue'
</script>

MyCounter.vue 引用 MyCounter,並在 HTML template 使用兩個 MyCounter

以上並沒有任何黑魔法就可使每個 component 有自己的 count state 不互相影響,這都是拜 Module Pattern 與 Closure 之賜

Conclusion

  • Component 與 Module 都能處理重複部分,唯 Component 是在處理重複 HTML;而 Module 是在處理重複 JavaScript
  • Vue 3 的 module 本質就是 Module Pattern 與 Closure 應用,這使得每個 component 都有自己的 state,卻又能共享 JavaScript