Vue 3 以 emit
發出 Event,但這種方式不方便 Point-free,Vue3-fp 提供了 eject
將 emit
轉成適合 Point-free 版本。
Version
Vue 3.2
Vue3-fp 0.3.2
Compsition API
當按下 +
對 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
結果不變,但使用 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
propwrite (innerCount)
:寫入innerCount
state
17 行
let onClick = pipe (
read (innerCount),
inc,
write (innerCount),
eject (emits) ('change')
)
使用 pipe
組合 onClick()
:
read (innerCount)
:讀取innerCount
stateinc
:使值遞增write (innerCount)
:寫入innerCount
stateeject (emits) ('change')
:使用eject
將emits
轉成 curry function 發出change
event
10 行
let eject = curryN (2)
eject
只是使用 curryN()
將 emits
轉成適合 Point-free 版本。
Vue3-fp
結果不變,但使用 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