點燈坊

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

使用 Module 取代 Vuex

Sam Xiao's Avatar 2021-08-27

Vue 2 若要 Component 間共享 State,Vuex 算是最簡單方式,但若需求簡單,則 Vuex 又過於麻煩,Vue 3 可簡單使用 Module 取代 Vuex。

Version

Vue 3.2

State Management

sm000

雖然有兩個 <MyCounter>,但只要按下任一 + 都會使 count 遞增,也就是兩個 component 會共用 count state,且同時對其 reactive。

Page

App.vue

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

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

同時使用兩個 <MyCounter>

Component

MyCounter.vue

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

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

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

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

Module

useCounter.js

import { ref } from 'vue'

let count = ref (0)

export default _ => {   
  let onClick = _ =>  count.value++
  
  return {
    count,
    onClick
  }
}

第 3 行

let count = ref (0)

count state 搬出 function,因為沒有 function 保護,因此喪失 Closure 機制,count state 成為 global data,又因為 ref 自帶 reactive,因此所有 component 都會自動改變。

可發現在 Vue 3 不見的要使用 Vuex 才能讓 component 共享 state,可簡單使用 module 與 global data 就能實現

Point-free

useCounter.js

import { ref } from 'vue'
import { read, write } from 'vue3-fp'
import { inc, pipe } from 'ramda'

let count = ref (0)

export default _ => {
  let onClick = pipe (
    read (count),
    inc,
    write (count)
  )

  return {
    count,
    onClick
  }
}

第 8 行

let onClick = pipe (
  read (count),
  inc,
  write (count)
)

onClick 亦可使用 pipe 組合,如此就不用處理 .value

Conclusion

  • Module 配合 global data 使 Vue 3 有了新用法,不再為了要讓 component 間共享 state 而使用 Vuex,可簡單使用 module 即可