點燈坊

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

如何從 Object 取出 Property 寫入 State ?

Sam Xiao's Avatar 2021-07-09

一般會從 API 取出 Value 後再寫入 State,但也可只取出 Object,再透過 ap 從 Object 取出 Property 並寫入 State。

Version

Vue 3.0.11

Promise

ap000

按下 Get Book 會從 API 獲得 title

api/getBook.js

import axios from 'axios'

export default id => _ => axios.get(`/book/${id}`)

使用 axios.get 回傳 Promise。

App.vue

<template lang='pug'>
div
  button(@click='onClick') Get Book
div {{ title }}
</template>

<script setup>
import { ref } from 'vue'
import { write } from 'vue3-fp'
import { andThen as then, otherwise } from 'ramda'
import S from 'sanctuary'
import { error } from 'wink-fp'
import getBook from '/src/api/getBook'

let { unchecked: { pipe, ap, prop, props }} = S

let title = ref ('')

let errorHandling = pipe ([
  props (['response', 'data', 'error']),
  error
])

let onClick = pipe ([
  getBook (1),
  then (prop ('data')),
  then (ap ({ title: write (title) })),
  otherwise (errorHandling)
])
</script>

17 行

let title = ref ('')

使用 ref 定義 title state 較適合 Point-free。

24 行

let onClick = pipe ([
  getBook (1),
  then (prop ('data')),
  then (ap ({ title: write (title) })),
  otherwise (errorHandling)
])

使用 pipe 組合 onClick

  • getBook (1):將 id 傳入 getBook 回傳 Promise
  • then (prop ('data')):從 Resolved Promise 內取出 data,回傳為 Object
  • then (ap ({ title: write (title) })):從 Resolved Promise 內的 Object 取出 title property 並寫入 title state,這連續動作可使用 Sactuary 的 ap 一步完成
  • otherwise (errorHandling):傳入 errorHandling 處理 Rejected Promise

19 行

let errorHandling = pipe ([
  props (['response', 'data', 'error']),
  error
])

使用 pipe 組合 errorHandling

  • props (['response', 'data', 'error']):在 Rejected Promise 內取出 response.data.error
  • error:印出錯誤訊息

Future

api/getBook_.js

import axios from 'axios'
import { encaseP } from 'fluture'

export default id => _ => encaseP (axios) (`/book/${id}`)
  • encaseP:將 axios 轉成回傳 Future 的 function 後,再傳入 url

App.vue

<template lang='pug'>
div
  button(@click='onClick') Get Book
div {{ title }}
</template>

<script setup>
import { ref } from 'vue'
import { write } from 'vue3-fp'
import S from 'sanctuary'
import { error } from 'wink-fp'
import { fork, mapRej } from 'fluture'
import getBook from '/src/api/getBook_'

let { prop, props, unchecked: { pipe, map, ap }} = S

let title = ref ('')

let onClick = pipe ([
  getBook (1),
  map (prop ('data')),
  mapRej (props (['response', 'data', 'error'])),
  fork (error) (ap ({ title: write (title) }))
])
</script>

19 行

let onClick = pipe ([
  getBook (1),
  map (prop ('data')),
  mapRej (props (['response', 'data', 'error'])),
  fork (error) (ap ({ title: write (title) }))
])

使用 pipe 組合 onClick

  • getBook (1):將 id 傳入 getBook 回傳 Future
  • map (path (['data'])):在 Resolved Future 內取得 data,回傳為 Object
  • mapRej (path (['response', 'data', 'error'])):在 Rejected Future 內取得 response.date.error
  • fork (error) (ap ({ title: write (title) })):從 Future 內處理 Rejected Future,並從 Resolved Future 內的 Object 取出 title property 並寫入 title state,這連續動作可使用 Sactuary 的 ap 一步完成

Conclusion

  • 從 Object 取出 property 並寫入 state 為常見需求,透過 ap 可一步完成

Reference

Sactuary, ap