はじめに
フロントエンドエンジニアの松田です。 最近Notionというアプリを使い始めてなかなか便利だなーと思っています。
Vue.jsを3ヶ月ほど前から使ってそこそこ慣れてきたので、2年ぐらい使ってきたReact.jsとの比較をしてみます。 どちらも利点があるので、迷った時や「そうだよねー」という気持ちを得たい際にご参考ください。
TL;DR
- React, Vueともに良い点がある
- React.jsはHTML/CSSまできちんと型定義できる
- Vue.jsはHTML/CSS/JSが個別に定義されていて理解しやすい
React.js vs Vue.js
基本的な文法
コンポーネント
基本的なコンポーネントの記述を比較してみましょう。 React.jsはVue.jsよりもシンプルに見えますが、Vue.jsはtemplateタグなどで役割をわかりやすく分割しているとも言えます。
HTMLの記述は、React.jsではjsxを、Vue.jsではテンプレートを使います。 jsxではtemplateタグを使うことなくシンプルに書けます。 しかし、classNameやhtmlForなど、JavaScriptに存在する構文とのバッティングを避けるために独自の属性名を使わなければいけない箇所があります。
CSSの記述については、Vue.jsではScoped CSSが最初から使えるのが大きな特徴です。 React.jsでは通常のCSSを利用する、もしくはstyled-componentsやemotionなどを導入して、ScopedなCSSを利用する選択肢があります。 styled-componentsのCSS記述が独特な部分もあり、初めて使う場合は学習が必要です。 CSSについてはReact.jsよりもVue.jsのハードルが低いと言えそうです。
JavaScriptについては、React.jsの方がシンプルに見えます。Vue.jsではnameプロパティなど、独自のプロパティ名を使って定義をするため冗長に見えます。
また、Vue.jsは公式のドキュメントなどでもexport default
が使われていて、eslintのprefer-default-exportをtrueにしづらい空気感があります。
React.js
const ReactComponent = () => {
return <div className="hello">Hello, World!</div>;
};
Vue.js
<template>
<div class="hello">Hello, World!</div>;
</template>
<script>
export default {
name: 'VueComponent'
}
</script>
<style scoped>
.hello {
font-size: 16px;
}
</style>
表示制御
React.jsではJavaScriptのif文を使うのに対して、Vue.jsでは独自のディレクティブを使います。これは好みが別れる部分でしょう。 Vue.jsでは独自のディレクティブで簡単に書ける一方で、どのようなディレクティブがあるのか知っておかないと、ディレクティブで表現できることを実装してしまう可能性があります。 React.jsでは通常のJavaScriptを利用するので、表示と処理を分離しやすいです。
React.js
const ReactComponent = props => {
if (props.isHidden) {
return null;
}
return <div>Hello, World!</div>
}
````
##### Vue.js
```vue
<template>
<div v-if="isHidden">Hello, World!</div>;
</template>
<script>
export default {
name: 'VueComponent',
computed: {
isHidden() {
return true;
}
}
}
</script>
<style scoped>
</style>
コンポーネント分割
React.jsとVue.jsでのコンポーネントを利用する場合の構文を比較してみます。 React.jsではimportしてそのまま使えるのに対して、Vue.jsの場合はcomponentsに加えるというステップがあります。 大量にコンポーネント分割を行う場合は、React.jsの方がわずかですが作業量が少なくてすみます。
React.js
// ChildComponent.js
const ChildComponent = () => {
return <div>child component</div>;
};
// ParentComponent.js
import { ChildComponent } from 'ChildComponent';
const ParentComponent = () => {
return (
<div>
<ChildComponent/>
</div>
);
};
Vue.js
// ChildComponent.vue
<template>
<div>child component</div>
</template>
<script>
export default {
// ...
}
</script>
// ParentComponent.vue
<template>
<child-component/>
</template>
<script>
import ChildComponent from 'ChildComponent'
export default {
components: {
ChildComponent
}
}
</script>
型定義
TypeScriptでの型定義を比較してみます。Vue.jsでflowを使った経験がないため、ここではTypeScriptで比較しています。
型定義に関しては、個人的な所感になりますがReact.jsが圧倒的に使いやすいです。 Vue.jsではtemplateでの型安全を保証しづらい(ランタイムエラーは出ます)ため、コーディング段階ではReact.jsの方がミスを防ぎやすいです。 また、Vue.jsでは型定義にStringやNumberなどTypeScriptの型を利用できません。vue-property-decoratorを使うことで緩和することはできますが、templateタグを厳密に型安全にすることはできません。
React.js
// ChildComponent.js
import * as React from 'react';
type Props = {
name: string;
};
const ChildComponent: React.SFC<Props> = props => {
return <div>Hello, {props.name}!</div>;
};
// ParentComponent.js
import { ChildComponent } from 'ChildComponent';
const ParentComponent = () => {
// TS2322: Type '1' is not assignable to type 'string'.
return (
<div>
<ChildComponent name={1}/>
</div>
);
};
Vue.js
// ChildComponent.vue
<template>
<div>Hello, {{ name }}</div>
</template>
<script>
export default {
props: {
type: String,
required: true,
default: 'mike'
}
}
</script>
// ParentComponent.vue
// type check failed for prop "name". Expected String, got Number.
<template>
<child-component
:name="1"/>
</template>
<script>
import ChildComponent from 'ChildComponent'
export default {
components: {
ChildComponent
}
}
</script>
ライブラリ開発体制
それぞれのルーティングライブラリを比較してみます。 React.js本体はfacebookのリポジトリとして登録されていますが、react-routerはReactTrainingのリポジトリです。 一方、Vue.jsは本体とvue-routerともに、vuejsのリポジトリとして登録されています。
各開発者や各コミュニティでライブラリのリポジトリを持っているか、本体のコミュニティで持っているかは微妙な差ですが、開発する際には影響があります。 React.jsでは定番ライブラリはあるものの、類似したライブラリが多くありどれを使えば良いか悩んでしまう場面があります。 一方Vue.jsのライブラリを選ぶ際は、vuejsのリポジトリがなければ別のライブラリを探すという流れになるため、少しハードルが下がるのではないでしょうか。
まとめ
React.js, Vue.jsどちらとも面白い部分があり、逆にツラい部分もあります。 ですが、共通するのはどちらも使っていて楽しいということです。 どちらも一長一短ありますが、引き続きどちらも使っていき、また知見が溜まってきたら共有します。 読んでいただきありがとうございました。