點燈坊

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

使用 mark 讀取 Prop

Sam Xiao's Avatar 2021-08-25

Vue 3 要以 props.name 形式讀取 prop,但這種方式不方便 Point-free,Vue3-fp 提供了 Curry Function 版本的 mark

Version

Vue 3.2
Vue3-fp 0.3.2

Composition API

mark000

將 prop 傳給 state,按下 + 將對 state 遞增。

App.vue

<template>
  <MyCounter :start="outerCount"/>
</template>

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

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

第 6 行

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

引用 MyCounter component。

第 8 行

let outerCount = $ref (3)

定義 outerCount state 的初始值為 3

MyCounter.vue

<template>
  <span>{{ innerCount }}</span>
  <button @click="onClick">+</button>
</template>

<script setup>
let innerCount = $ref (0)
let props = defineProps ({ start: Number })

innerCount = props.start
let onClick = _ => innerCount++
</script>

第 8 行

let props = defineProps ({ start: Number })

使用 defineProps 定義 start prop。

第 7 行

let innerCount = $ref (0)

定義 innerCount state 的初始值為 0

10 行

innerCount = props.start

start prop 值寫入 innerCount state。

Vue 3 要求我們以 props.name 形式讀取 prop

11 行

let onClick = _ => innerCount++

當按下 + button 將對 innerCount state 遞增。

Point-free

mark000

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

App.vue

<template>
  <MyCounter :start="outerCount"/>
</template>

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

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

App.vue 沒有改變。

MyCounter.vue

<template>
  <span>{{ innerCount }}</span>
  <button @click="onClick">+</button>
</template>

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

let mark = thunkify (prop)

let innerCount = ref(0)
let props = defineProps ({ start: Number })

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

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

22 行

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

使用 pipe 組合 IIFE:

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

11 行

let mark = thunkify (prop)

Vue 3 需以 props.name 形式讀取 prop,但這種方式並不適合 Point-free。

其實 prop 讀取方式很類似 Ramda 的 prop,因此以 prop() 為基礎加以 thunkifymark 就很適合 Function Pipeline。

16 行

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

使用 pipe 組合 onClick

  • read (innerCount):讀取 innerCount state
  • inc:對值遞增
  • write (innerCount):寫入 innerCount state

Vue3-fp

mark000

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

App.vue

<template>
  <MyCounter :start="outerCount"/>
</template>

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

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

App.vue 沒有改變。

MyCounter.vue

<template>
  <span>{{ innerCount }}</span>
  <button @click="onClick">+</button>
</template>

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

let innerCount = ref(0)
let props = defineProps ({ start: Number })

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

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

第 8 行

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

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

mark :: String -> Data -> () -> a
由 props 讀取指定 prop

String:傳入指定 prop

Data:傳入 props

() -> a:回傳 Thunk

Conclusion

  • 為了 Point-free 常將 function 加以 thunkify,如 read 也是 thunkify (unref)