點燈坊

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

Vue Router 使用 Functional API

Sam Xiao's Avatar 2020-11-11

傳統 Vue Router 都以 this 使用,這使得 Extract Function 時還必須將 Vue Instance 傳進 Function,事實上 Vue Router 也能不使用 this,直接 Import Router 使用,甚至更進一步 Point-free。

Version

Vue 2.6.11
Vue-router 3.2.0

Options API

<template>
  <div id="app">
    <div id="nav">
      <a @click.prevent="onHomeClick" href="#">Home</a> |
      <a @click.prevent="onAboutClick" href="#">About</a>
    </div>
    <router-view/>
  </div>
</template>

<script>
let onHomeClick = function() {
  this.$router.push('/')
}

let onAboutClick = function() {
  this.$router.push('/about')
}

export default {
  methods: {
    onHomeClick,
    onAboutClick,
  }
}
</script>

12 行

let onHomeClick = function() {
  this.$router.push('/')
}

若要使用 Vue Router 的 push(),傳統必須使用 this.$router,這使得 extract function 時必須考慮 this 將 Vue Instance 傳進 function。

Functional API

<template>
  <div id="app">
    <div id="nav">
      <a @click.prevent="onHomeClick" href="#">Home</a> |
      <a @click.prevent="onAboutClick" href="#">About</a>
    </div>
    <router-view/>
  </div>
</template>

<script>
import router from '@/router/index'

let onHomeClick = () => router.push('/')

let onAboutClick = () => router.push('/about')

export default {
  methods: {
    onHomeClick,
    onAboutClick,
  }
}
</script>

12 行

import router from '@/router/index'

將實際 router 引入。

14 行

let onHomeClick = () => router.push('/')

直接以 router 使用 push(),由於沒使用 this,可直接使用 arrow function,extract function 時也不用再傳入 Vue Instance。

Point-free

<template>
  <div id="app">
    <div id="nav">
      <a @click.prevent="onHomeClick" href="#">Home</a> |
      <a @click.prevent="onAboutClick" href="#">About</a>
    </div>
    <router-view/>
  </div>
</template>

<script>
import { pipe, always, bind } from 'ramda'
import router from '@/router/index'

let push = bind(router.push, router)

let onHomeClick = pipe(
  always('/'),
  push
)

let onAboutClick = pipe(
  always('/about'),
  push
)

export default {
  methods: {
    onHomeClick,
    onAboutClick,
  }
}
</script>

15 行

let push = bind(router.push, router)

使用 bind()router 抽出 push() free function。

17 行

let onHomeClick = pipe(
  always('/'),
  push
)

使用 pipe() 組合出 onHomeClick()

Conclusion

  • Vue 有多種寫法,其實不見得什麼都要使用 this ,Vue Router 透過引用實際 router 可直接使用 push(),不用再擔心很難處理 this
  • 既然不必使用 this,可使用 bind() 抽出 push(),進一步使用 Function Pipeline 組合