はじめに
株式会社GROWTH VERSE(以下GV)でフロントエンドエンジニアをしている杉浦です。業務ではVueを利用してAIMSTARの画面を開発しています。また、新規プロダクトをNextで開発しています。GVに入社する前は業務・個人開発等で主にReactを5年ほど書いていました。
この記事では、もともとReactを書いていた私が、Vueを書き始めた際に感じた、違和感や気づきをお伝えすることで、これからVueに挑戦しようとしているReact開発者の一助になれば幸いです!
*この記事では、Next.jsやNuxt.jsなどのSSRのフレームワークについて触れていません、Viteを使ったSPAの開発を前提にお話しします。
TL;DR
React開発者がVueでの開発に混ざったことで気付いた点をまとめると以下です。
- コンポーネント設計で考慮することはほぼ一緒
- Custom Hooksを使ったロジックの分離もComposableAPIを使えば実現可能
- TypeScriptのサポートの心配はVueのバージョンが上がっていれば不要
- Vue.js Devtoolsがとても使いやすい
- 最低限必要なライブラリは大体揃っているが、Reactほど多くはない
- レンダリングの最適化について考える必要がない
- slot + emitが曲者で最初はつまづく
好みや個人差はあると思いますが、私が想定していたよりも、VueとReactの間に書き心地において大きな違いはありませんでした。それぞれについて、深ぼって説明していきたいと思います。
*この記事執筆時点での、最新版のVueの安定バージョンは v3.4.33
、Reactの安定バージョンは 18.3.1
となっています。
コンポーネント設計
宣言的UIのライブラリ(ReactやVue)を使う上で、コンポーネント設計を理解する、また自分で設計することがあると思います。これら二つの作業において、ReactとVueで気をつける観点はそこまで変わらないです。フロントエンドのデザインパターンがまとまった https://www.patterns.dev/ をみた場合でも、 Container / Presentational Pattern
の記述はReactとVueどちらにもあり、一般的にもそうなのだろうと思っています。
UIとロジックの分離
UIとロジック記述の責務を分離するという考えは、先ほどの Container / Presentational Pattern
とも通じる部分がありますが、こちらについてもReactとVueにおいては違いはほぼありません。ただし、Vue3以降においては、という注意書きを添えておきます。Reactではこれをcustom hooksを使ってロジックを切り出して実現するのが一般的だと思いますが、VueではVue3以降だとComposables APIという概念と機能を使ってこれを実現できます。
そもそも、UIとロジックの分離については、宣言的UIと深く関わる概念であるため、宣言的UIを実現するためのライブラリ・フレームワークであるReact・Vueはこの点において共通点が多いことは自然な文脈だと思っています。
hooksとcomposition APIの対応関係は以下のように整理できます。
状態変数 | キャッシュ | 状態変数の監視 | グローバルなデータの受け渡し | |
---|---|---|---|---|
React hooks | useState / useReducer | React.memo, useMemo, useCallback | useEffect | useContext |
Composition API | ref() | computed() | watch() | provide / inject |
https://ja.vuejs.org/guide/extras/composition-api-faq#comparison-with-react-hooks
Typescriptサポート
Vueに触れていない時には、X・Twitterなどで「VueはTSに完全に対応していないから使いずらい」などの噂を耳にしていたので、気構えていましたが、これは杞憂でTypeScriptの恩恵を受けながら開発することができています。
しかし、注意点があります。Vueでは defineXXX
のような命名ルールの関数を使って .vue
ファイル上のpropsやemitsに型を定義していくのですが、Vueのバージョンアップとともに、 defineXXX
も拡充されているので、Vueのバージョンによっては、使いたい型定義の関数が使えない場合に遭遇する可能性はあります。例えば、 defineSlot
というslotsに型定義を付与する関数はバージョン3.3以降で使える関数であるため、それ以前のVueのバージョンでは、slots
にわたるコンポーネントのpropsなどはany型になってしまいます。ただ、バージョンさえあげればこれは問題ないです。
また、IDEとの連携をVueの標準拡張機能を使えば、vueファイルであっても、型に基づいた補完機能も働いてくれるので、他のts / tsxファイルと同様の開発体験が提供されます。
https://marketplace.visualstudio.com/items?itemName=Vue.volar
ブラウザ開発者ツール
Reactでの開発の際に、React Developer ToolsをChrome等に入れて開発をしていた方は多いと思います。コンポーネントの各Stateが見れたり、画面上のUIに対応するコンポーネントが見れたり、便利でした。Vueでも Vue Devtools というブラウザ開発者用ツールがあり、これを使って、ほぼ同じことができます。
さらに、Vue Devtoolsのとても良い機能があり、それは、コンポーネントへのジャンプ機能です。開発者ツール上のコンポーネントの画面から、vscodeでの同コンポーネントが記述された .vue
ファイルを開いてくれます。非常に強力で便利です。
ライブラリ・エコシステム
エコシステムについてVueよりもReactの方が発展していることは、なんとなく皆さんご存知だと思っております。実際にはその通りで、ReactとVueのnpm install
数を見ても納得感があります。
本筋とは関係ないのですが、皆様もグラフを見てお気づきの通り、2022年終わりにvueとsvelteで不自然なスパイクがあります。この要因についてしらべても私が調べてもわかりませんでした。いったい何があったのか、もしご存知の方いらしたら、コメント等で教えてください!
さて、話を本筋に戻します。エコシステムの大きさはReactには劣るものの、Vueでも開発において必須となるようなライブラリはきちんと整備されているので、Reactにはあったのに、Vueにはない!みたいな状況は未だに遭遇していないです。 vite
TanStackQuery
vue-router
vue-i18n
pinia
Nuxt
などが代表的な例です。
スタイリング | ルーティング | 状態管理 | フェッチライブラリ | SSR / SSG | |
---|---|---|---|---|---|
React | - CSS Module - Tailwind CSS - CSS in JS(s) - Zeroruntime CSS in JS(s) |
- react-router | - redux - recoil - Jotai |
- TanStack - SWR |
- Nextjs / page-router - Nextjs / app-router - remix |
Vue | - style - Tailwind CSS |
- vue-router | - pinia | - TanStack | - Nuxtjs |
*そもそも、Composables APIでtsファイルが使えるので、vueに依存関係のないライブラリは基本全て使えるはずです。
個人的に特筆したいのは、CSSライブラリについてです。ReactではCSSライブラリの戦国時代になっていると思いますが、Vueではそのようなことはあまり起きていないようです。Vueファイルのstyleタグに書く、もしくはTailwind CSSを使う。になるからです。ですので、基本的には CSS Modules
のようにcssやscssを(場合によっては)scopedな形で記述していくのが基本です。
cssライブラリの学習コストがほぼないので、New Joinerにはありがたい点でもあります。
レンダリング最適化
仮想DOMによるレンダリングの最適化が、ReactやVueのコンセプトとしてありました。その上でReactではstateをメモ化して不要なレンダリングを防ぐためのtipsがいくつかあります。 React.memo
useMemo
useCallback
を組み合わせて最適化を自分でやるのが、Reactの特徴です。
一方で、Vueはほぼ全てVueにお任せで実装するのが特徴です。値のメモ化に関しては computed()
というComposables APIを使えばよしなにやってくれます。この点が、Vueの敷居が低い点にもなっていそうです。公式ドキュメントでも力強くその点をアピールしています。
これは余談ですが、ReactでもReact Compilerが試用段階にあり、複雑なメモ化のカスタマイズを解決しようという動きがあるのかもしれません。
Slot + Emit
私が一番つまづいたのが、Vueのslot
とemit
という仕様になります。それぞれの仕様については公式ドキュメントがわかりやすいの、そちらで確認するのがベストです。
emit
は親子コンポーネント間でのイベントに対するイベントハンドラの渡し型のメンタルモデルが違うので初めは戸惑うかもしれません。Reactはイベントハンドラを親で定義して子にpropsで渡す。という気持ちで書くと思うのですが、Vueではイベントを子から親に渡して処理します。
slot
はReactの children
に似たような機能で、コンポーネントを親から子に渡すことができるものですが、大きな違いとして、子コンポーネントから親コンポーネントに状態を渡すことができます。公式ドキュメントだとこちらに記載があります。この機能があるため、データの流れについて親から子に向かって辿っていくコードの読み方をしているとつまづきますので注意が必要です。
おわりに
この記事を通じて、ReactからVueの開発に移行する際に直面するであろう主な違いや類似点について概観しました。どちらのフレームワークも強力であり、それぞれ独自の哲学と利点があります。Reactを長年使用してきた私としては、Vueの学習過程で遭遇したいくつかの挑戦や発見は新鮮で興味深いものでした。
Vueに関するさらなる探求や、私たちのプロダクト開発チームへの参加に興味がある方は、ぜひGROWTH VERSEでのキャリアを考えてみてください。新しい技術への挑戦、そしてそれを通じた成長をサポートする環境を提供しています。
私たちと一緒に、技術の限界を押し広げ、次世代のウェブアプリケーションを創り出しましょう。興味がある方は、以下のリンクから詳細をご覧ください。
この記事が、ReactからVueへの移行を検討している方々にとって有益な情報となれば幸いです。また、皆さんのフロントエンド開発の旅が、より充実したものになることを心より願っています。