91
52

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue #3Advent Calendar 2019

Day 13

2020年のVue.jsとReactの選定基準を考える(Hooks vs Composition API)

Posted at

Vue.jsの次メジャーバージョン(v3)が2020年Q1にリリースされる。特に目新しいのが、Vue Composition APIという、これまでのVueの書き方とは違う関数ベースのAPI。

これに伴って、Vue.jsとReactの選定基準についても改めて考えないとなぁと思い書いた。
今回はまず新しいVue Composition APIに触れて、最後にReactとの違いについて書いてみる。

TL;DR(忙しい人向け)

  • TypeScript前提ならReact
  • TypeScriptを使わない(or 使えない)規模ならVue.js
  • 既存の大規模Vue.jsプロジェクトは、徐々にComposition APIに移行すると幸せ

Vue.js 3の Composition API とは

Composition APIでは、下のコードのように、reactivecomputedといった関数を用いて組み立てていく。見て分かる通り、今までとは全く違う、React Hooksと近しい書き方になる。

vue3-component.vue
<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0, // data: { count: 0 } と同じ
      double: computed(() => state.count * 2) // computed: { double: () => { this.count * 2 } } と同じ
    })

    // methods: { increments() { this.count++ } } と同じ (下でsetupからreturnしているため)
    function increment() {
      state.count++
    }

    // template内で使いたいものを返す
    return {
      state,
      increment
    }
  }
}
</script>

このComposition APIを触ってみた時は興奮したんだけど、冷静になって考えてみると、Vue.jsの存在意義ってなんだろうとふと思った。

なぜVue.jsにComposition APIが実装されたか

Composition APIのRFCでも書かれているが、このAPIが誕生した理由は2つある。
https://vue-composition-api-rfc.netlify.com/#motivation

  • ロジックの抽出と再利用性
  • TypeScript(型推論)の改善

ロジックの抽出と再利用性

VueはComponentの分割手法として、Mixinを提供していたが、Mixinでは2つの問題があった。

Mixinの1つ目の問題は**「Mixinにどのようなメソッドなどがあるかを、Mixinを利用する側から一見して分からない」**こと。

vue2-component.js
export default {
  mixins: [myGreatMixin] // mixinが何を提供しているかはファイルを見ないと分からない
}

Mixinの2つ目の問題は、**「Mixinの中でしか用いないメソッドなどをprivateにすることができない」**こと。
Vue.jsのスタイルガイドでは$_mixinName_methodNameのようにprefix付きで命名することを強要している。

vue2-component.js
const myGreatMixin = {
  methods: {
    publicMethod: function () {
      console.log('Hello from public')
    },
    $_myGreatMixin_privateMethod: function () { // 親からも呼べてしまう
      console.log('Hello from private')
    }
  }
}

これら2つの問題により、Vueが提供しているMixinは、可読性やメンテナンス性において良いものとは言えない。Mixinの中でさらにMixinを使う場合なんかは、正直書いていて楽しくない。

それに対しVue Compostion APIでは以下のように書くことができる

vue3-component.js
export default createComopnent({
  setup() {
    const { hello } = useSayHello()

    onMounted(() => {
      hello() // 'Hello'
    })
  }
})

// lib/say-hello.js
export const useSayHello = () => {
  const hello = () => {
    console.log('Hello')
  }
  return { hello }
}

比較して分かる通り、Composition APIではconst { hello } = useSayHello()といった具合に、抽象化されたコードがどのようなメソッドやデータを提供しているかひと目で分かる。またプライベートなデータもreturnしない限りスコープを閉じることができる。

2. TypeScript(型推論)の改善

これは現状、Vue.jsとTypeScriptの相性が悪いという問題を抱えているためである。

例えばVue.extend()内で、mixinが提供するメソッドなどに対して型推論する場合は、以下のように、そのmixinが提供するメソッドなどを全て個別に型定義しなければいけない。

vue.d.ts
declare module 'vue/types/vue' {
  interface Vue {
    items: Item[] // 「itemsというdataを提供するmixin」のための定義
    setSnackbar: (message: string) => void // 「setSnackbarというメソッドを提供するmixin」のための定義
  }
}

これでは、Mixinとは別に型を二重定義する必要があり、本来バグを防ぐためのTypeScriptが逆にバグの温床になってしまう。しかしComposition APIは純粋な関数であるため、特に工夫をせずとも型推論ができる。

TypeScriptデコレータによる推論は廃止

一時期、Vueをvue-property-decoratorなどのTypeScriptデコレータを使って型推論をするという流れがあり、Vue 3でもクラスベースのAPIを公式に提供しようかという話が挙がっていた。
しかしTypeScriptデコレータ自体まだexperimental(実験的)な機能であるため、その話は議論の末に捨てられてしまった。
詳細はIssueにある。[Abandoned] Class API proposal by yyx990803 · vuejs/rfcs · GitHub

Composition APIの登場

以上の諸問題によって、Vue.js は関数ベースのComposition APIを提供することを策定した。

Vue.js 2でもComposition APIを試せるようにプラグインを提供している。
https://github.com/vuejs/composition-api

Vue.jsとReactはどちらを選ぶべきか

早速本題に入ってみる。

TypeScriptならReact

まず、「はじめからTypeScriptで書く」というプロジェクトにおいては、Reactを選択するべきだと思う。Vue.jsであればComposition API自体がまず正式リリースされていないし、バージョン2の書き方は先に挙げたTypeScriptとの相性問題がある。それなら安定したReact Hooksを選ぶのが間違いない。

ではComposition APIが正式リリースされた際はどうすればいいか?。少し悩ましいがこれも自分の答えはReact。Composition APIから後発ならではの良さというのも特に感じなかったし、vuexやvue-routerといった周辺ツールに関しては、概念はReact系と一緒なのでそれほど学習コストに差はない。

またReactのコミュニティとの差を感じることもたまにある。例えばマテリアルデザインのUIライブラリにおいて、Vue.jsベースのVuetify.jsよりもReactベースのMaterial-UIがライブラリとして完成度が高い。他のライブラリのケースも、ほぼReactの方が安定して開発されている場面によく会う(2021年はそれほど変わらなくなると思うけど)。

いつVue.jsを使うべきなのか

Vue.jsは、TypeScriptやReactの習熟度が高くないチームであったり、小規模なケースにおいて採用することで強みを発揮できる。

そもそもVue.jsは、親しみやすいインタフェースである程度の複雑なアプリケーションを作れる、といった点がユーザーに愛されていた点だと思っている。Mixinを使わなければVue.jsは読みやすく、それほどJavaScriptに精通していなくとも書くことができる。

またSSRアプリケーションのフレームワークとしてReactのNext.jsよりも、Vue.jsのNuxt.jsの方が予め用意してくれている領域が広く、サクッとモダンなアプリケーションを作ることができる。

そういった点でも、Vue.jsはReactよりも小規模なプロジェクトに向いている。

いつComposition APIを使うべきか

Composition APIは、既にVue.jsを導入しているプロジェクトで有用な選択肢になる。

というのも、Vue2の記法自体は3でも使うことができ、Composition APIとも併用して動かすことができる。そのため、今現在運用しているVue 2のプロジェクトがTypeScriptを欲しくなるような規模になれば、部分的にComposition APIへ移行し、TypeScriptの強化とコードの抽象化を行うことができる。

所感

2020年の選定基準について、一通り書いてみた。

Vue.jsが型推論を考慮せずに設計されたこともあり、JavaScript界隈において少し曖昧な立ち位置になっているなぁと感じる。こういったVue.jsのAPIの拡張はメリットもある一方、ユーザーにとって選択疲れを引き起こしてしまっている。
もういっそのことTypeScriptを捨てて、バージョン2の書き方で貫き通してもよかったんじゃないかなぁと、少し思った。

91
52
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
91
52

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?