點燈坊

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

使用 eject 發出 Event

Sam Xiao's Avatar 2021-08-25

Vue 3 以 emit 發出 Event,但這種方式不方便 Point-free,Vue3-fp 提供了 ejectemit 轉成適合 Point-free 版本。

Version

Vue 3.2
Vue3-fp 0.3.2

Compsition API

eject000

當按下 + 對 counter 遞增時,會即時將 data 透過 event 由內往外傳。

App.vue

<template>
  <MyCounter :start="outerCount" @change="onChange"/> 
  {{ outerCount }}  
</template>

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

let outerCount = $ref (3)
let onChange = x => outerCount = x
</script>

第 7 行

import MyCounter from '/src/components/MyCounter.vue'

引用 MyCounter component。

第 2 行

<MyCounter :start="outerCount" @change="onChange"/> 

<MyCounter> 除了傳入 start prop 外,準備接收 change event 所傳出 data。

第 9 行

let outerCount = $ref (3)

建立 outerCount state 且初始值為 3

10 行

let onCountChange = x => outerCount = x

處理 change event,將接收值寫入 outerCount state。

MyCounter.vue

<template>
  <button @click="onClick">+</button>
</template>

<script setup>
let props = defineProps ({ start: Number })
let emits = defineEmits (['change'])

let innerCount = props.start

let onClick = _ => {
  innerCount++
  emits ('change', innerCount)
}
</script>

第 6 行

let props = defineProps ({ start: Number })

使用 defineProps 定義 start prop。

第 7 行

let emits = defineEmits (['change'])

使定 defineEmit 定義 emits,傳入為 Array,可同時定義多個 event。

第 9 行

let innerCount = props.start

startCount prop 指定到 innerCount state。

11 行

let onClick = _ => {
  innerCount++
  emits ('change', innerCount)
}

當按下 + button 時,除了 innerCount 遞增外,還將 innerCount 內部值透過 emits 發出 change event 傳出去。

Point-free

eject000

結果不變,但使用 Point-free 改寫。

App.vue

<template>
  <MyCounter :start="outerCount" @change="onChange"/> 
  {{ outerCount }}  
</template>

<script setup>
import { ref } from 'vue'
import { write } from 'vue3-fp'
import { pipe } from 'ramda'
import MyCounter from '/src/components/MyCounter.vue'

let outerCount = ref (3)

let onChange = pipe (
  write (outerCount)
)
</script>

14 行

let onChange = pipe (
  write (outerCount)
)

使用 pipe 組合 onChange

  • write (outerCount):將接收值寫入 outerCount state

MyCounter.vue

<template>
  <button @click="onClick">+</button>
</template>

<script setup>
import { ref } from 'vue'
import { read, write, mark } from 'vue3-fp'
import { pipe, curryN, inc } from 'ramda'

let eject = curryN (2)

let props = defineProps ({ start: Number })
let emits = defineEmits ([ 'change'])

let innerCount = ref (0)

let onClick = pipe (
  read (innerCount),
  inc,
  write (innerCount),
  eject (emits) ('change')
)

pipe (
  mark ('start') (props),
  write (innerCount)
) ()
</script>

24 行

pipe (
  mark ('start') (props),
  write (innerCount)
) ()

使用 pipe() 組合 IIFE:

  • mark ('start') (props):讀取 start prop
  • write (innerCount):寫入 innerCount state

17 行

let onClick = pipe (
  read (innerCount),
  inc,
  write (innerCount),
  eject (emits) ('change')
)

使用 pipe 組合 onClick()

  • read (innerCount):讀取 innerCount state
  • inc:使值遞增
  • write (innerCount):寫入 innerCount state
  • eject (emits) ('change'):使用 ejectemits 轉成 curry function 發出 change event

10 行

let eject = curryN (2)

eject 只是使用 curryN()emits 轉成適合 Point-free 版本。

Vue3-fp

eject000

結果不變,但使用 Vue3-fp 改寫。

App.vue

<template>
  <MyCounter :start="outerCount" @change="onChange"/> 
  {{ outerCount }}  
</template>

<script setup>
import { ref } from 'vue'
import { write } from 'vue3-fp'
import { pipe } from 'ramda'
import MyCounter from '/src/components/MyCounter.vue'

let outerCount = ref (3)

let onChange = pipe (
  write (outerCount)
)
</script>

App.vue 不變。

MyCounter.vue

<template>
  <button @click="onClick">+</button>
</template>

<script setup>
import { ref } from 'vue'
import { read, write, mark, eject } from 'vue3-fp'
import { pipe, curryN, inc } from 'ramda'

let props = defineProps ({ start: Number })
let emits = defineEmits ([ 'change'])

let innerCount = ref (0)

let onClick = pipe (
  read (innerCount),
  inc,
  write (innerCount),
  eject (emits) ('change')
)

pipe (
  mark ('start') (props),
  write (innerCount)
) ()
</script>

第 7 行

import { read, write, mark, eject } from 'vue3-fp'

Vue3-fp 已經提供 eject 可直接使用。

eject :: Function -> String -> Function
emits 轉成適合 Point-free 版本

Function:傳入 emits

String:傳入 event 名稱

Function:回傳 curry function 版本的 emits

Conclusion

  • 如同 prop 一樣,還是必須先用 defineEmits 建立 emits
  • emits 不方便 Point-free,使用 eject 轉成 curry function 才能 Point-free