點燈坊

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

將 Template Data 傳入共用 Observable

Sam Xiao's Avatar 2020-05-15

若多個 DOM Element 的處理邏輯相同,只有 Data 不同,可共用相同的 Observable 並傳入不同 Template Data 即可。

Version

macOS Catalina 10.15.4
WebStorm 2020.1
Vue 2.6.11
RxJS 6.5.5

Browser

pluck000

三個 button 各顯示不同 title,但底層都呼叫相同 API,只是傳入 id 不一樣而已。

Data

{
  "id": 2,
  "title": "RxJS in Action",
  "price": 200,
  "categoryId": 2,
  "image": "rxjs.jpg"
}

http://localhost:3000/books/2 回傳為以上 object。

Template Data

<template>
  <div>
    <button v-stream:click="{ subject: click$, data: 1 }">Show book 1</button>
    <button v-stream:click="{ subject: click$, data: 2 }">Show book 2</button>
    <button v-stream:click="{ subject: click$, data: 3 }">Show book 3</button>
    <h1>{{ title$ }}</h1>
  </div>
</template>

<script>
import { ajax } from 'rxjs/ajax'
import { exhaustMap, pluck } from 'rxjs/operators'

let fetchTitle$ = x => ajax(`http://localhost:3000/books/${x}`).pipe(
  pluck('response', 'title')
)

let subscriptions = function() {
  let title$ = this.click$.pipe(
    pluck('data'),
    exhaustMap(fetchTitle$)
  )

  return { title$ }
}

export default {
  name: 'app',
  domStreams: ['click$'],
  subscriptions,
}
</script>

第 3 行

<button v-stream:click="{ subject: click$, data: 1 }">Show book 1</button>
<button v-stream:click="{ subject: click$, data: 2 }">Show book 2</button>
<button v-stream:click="{ subject: click$, data: 3 }">Show book 3</button>

v-stream 除了可指定要綁定的 DOM event 與 Subject,還可指定要傳入 data,如此可多個 DOM element 同時使用相同 Observable。

14 行

let fetchTitle$ = x => ajax(`http://localhost:3000/books/${x}`).pipe(
  pluck('response', 'title')
)

fetchTitle() 呼叫 API 並回傳 title

19 行

let title$ = this.click$.pipe(
  pluck('data'),
  exhaustMap(fetchTitle$)
)

只需一個 title$ Observable 即可,使用 pluck() 動態取出 data property 的值。

pluck()
從 Observable 中的每個 object 的指定 property 取出值

pluck001

Observable 的每個 source value 對應一個 property。

Conclusion

  • 若使用 event 處理 asynchronous,可共用相同 event handler 並傳入不同 argument;在 FRP 也可共用相同 Observable,只要傳入不同 template data 即可

Reference

RxJS, pluck()
Vue-rx, v-stream: Streaming DOM Events