本サイトはプロモーションが含まれています

【2022年版】Vue3の最新の書き方をReactと比較しながら学んでみた【script setup構文】

導入

現代のフロントエンドといえば React.js と Vue.js の 2 強ですよね。
私は React には触れたことはあるので基本はある程度わかっているのですが、Vue は全く触れたことはありませんでした。
そこで今回は Vue3 の現時点(2022 年 5 月)で最新の書き方を、React と比較しながら学んでみます。


ちなみに私はフロントエンドを学んで日が浅いので、書き方がおかしいところがあるかもしれませんが、大目に見ていただけると嬉しいです m(_ _)m
(お問い合わせフォームでこっそり指摘していただけると非常に助かります)

構文変化の歴史

React も Vue も書き方は時が経つにつれて変化しています。
ここではそれぞれの違いを簡単に見ていきます。

React

React は大きく分けてクラスコンポーネントと関数コンポーネントに分かれます。

クラスコンポーネント

関数コンポーネントで state が管理できるようになるまでは、こちらの書き方が主流でした。
Java のようにクラスを作るのが特徴です。

class Counter extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0,
}
}
increase() {
this.setState({
count: this.state.count + 1,
})
}
render() {
return (
<div>
<p>合計:{this.state.count}</p>
<button onClick={() => this.increase()}>クリック</button>
</div>
)
}
}

関数コンポーネント

クラスの代わりに関数を使ってコンポーネントを定義します。
関数コンポーネントで state を管理できる React Hooks が登場してからはこちらが主流の書き方です。
より簡潔に書けます。

const Counter = () => {
const [count, setCount] = React.useState(0)
const increase = () => {
setCount(count + 1)
}
return (
<div>
<p>合計:{count}</p>
<button onClick={increase}>クリック</button>
</div>
)
}

Vue

Vue は Vue2(Options API)と Vue3(Composition API)に分かれ、Vue3 の中でも Vue3.2 以降は<script setup>構文が使えるようになりました。

Vue2 (Options API)

Vue2 ではコンポーネントを data()と methods に分けて書きます。
React のクラスコンポーネントに近い印象です。

<template>
<div>
<p>合計:{{count}}</p>
<button @click="increase">
クリック
</button>
</div>
</template>
<script>
import Vue from "vue";
export default Vue.extend({
data() {
return {
count: 0;
};
},
methods: {
increase() {
this.count++;
}
},
});
</script>

Vue3 (Composition API)

Vue3 では setup()内に data()と methods を ES6 以降の JavaScript のように書けるようになりました。
template 部分は Vue2 と変わりません。

<template>
<div>
<p>合計:{{count}}</p>
<button @click="increase">
クリック
</button>
</div>
</template>
<script>
import {defineComponent, ref} from "vue";
export default defineComponent({
setup() {
const count = ref(0);
const increase = () => {
count.value++;
};
return {
count,
increase,
};
},
});
</script>

Vue3.2 (<script setup>構文)

Vue3.2 以降では setup()内の記述を<script setup>を使うことで直接書けるようになりました。
React の関数コンポーネントの書き方とかなり近い印象があります。

<script setup>
import {ref} from "vue";
const count = ref(0);
const increase = () => {
count.value++;
};
</script>
<template>
<div>
<p>合計:{{count}}</p>
<button @click="increase">
クリック
</button>
</div>
</template>


Vue3 と React の最新の書き方の比較

ここからは、Vue3.2 以降の<script setup>を使った書き方を、関数コンポーネントを使った React と比較することで学んでいきます。


このために、以下の簡単な Web アプリを作って比較することにしました。
足し算器
これは増加量に 0 以上の数字を入れ、「足す」ボタンを押すとその増加量分合計に足されるものです。
「リセット」ボタンを押すと合計が 0 に戻ります。
また、入力に問題がある場合、アラートが出ます。


実際に完成したものはこちらにあるので、確認してみてください。
React 版はこちら
Vue3 版はこちら


それでは、React と比較しながら学んでみたいと思います。
以下のステップで学んでいきます。

  • プロジェクトの作成
  • プロジェクトの起動
  • 全体の構成
  • App コンポーネントの比較
  • Adder コンポーネントの比較
  • GitHub Pages へのデプロイ

プロジェクトの作成

まず、プロジェクトの作成方法の比較です。
Vue では、React のcreate-react-appの代わりにcreate-vueを使用します。


React

npx create-react-app sample-app

Vue3
(後の質問はすべて No で良い)

npm init vue@3 sample-app

TypeScript を使用する場合は以下のようにします。


React

npx create-react-app sample-app --template typescript

Vue3
(コマンドを打った後に出てくる質問の Add TypeScript?でYesと答える)

npm init vue@3 sample-app

これ以降の部分は TypeScript ではなく、JavaScript でコードを書いています。
TypeScript を使う場合は適宜変換してください。

プロジェクトの起動

ローカル環境で起動する場合のコマンドです。


React

npm start

Vue3

npm run dev

起動後の初期状態は、以下のようなおなじみの画面です。


React
create-react-app
Vue3
create-vue

全体の構成

足し算器完成後の全体の構成は大まかに説明すると以下のような流れになっています。


React
index.js(エントリーポイント) → App.js(画面全体) → Adder.jsx(足し算器)


Vue3
main.js(エントリーポイント) → App.vue(画面全体) → Adder.vue(足し算器)


詳しくはソースコードを確認してください。
React 版はこちら
Vue3 版はこちら


ここからはメイン部分の App コンポーネントと Adder コンポーネントについて比較していきます。

App コンポーネントの比較

まず App コンポーネントの比較です。
components ディレクトリから Adder コンポーネントを取り込んでいます。
また、css ファイルもインポートしてスタイルを適用しています。


比較するとわかりやすいのですが、Vue では HTML・CSS・JavaScript の部分をはっきりと区別していることがわかります。
一方 React は HTML・CSS・JavaScript を混在させた形です。
好みの問題だと思いますがどちらも似ているので、どちらかをマスターした方であれば、もう一方に対応するのはそれほど難しくないと思います。


React

import Adder from "./components/Adder"
import "./App.css"
const App = () => {
return (
<div className="App">
<header>
<h1>足し算器</h1>
</header>
<main>
<Adder />
</main>
</div>
)
}
export default App

Vue3

<script setup>
import Adder from './components/Adder.vue';
</script>
<template>
<div className="App">
<header>
<h1>
足し算器
</h1>
</header>
<main>
<Adder />
</main>
</div>
</template>
<style>
@import "./App.css";
</style>

Adder コンポーネントの比較

次に、state を含んだ Adder コンポーネントの比較です。
このコンポーネントでは、<input>タグに入力された数字をincreaseに保存し、「足す」ボタンをクリックするとincreaseだけ、合計を表すsumを増加させるという機能を持っています。
また、「リセット」ボタンをクリックするとsumが 0 になります。


2 つを比較すると、細かい部分で違いがありますが、概ね同じ構造であることがわかります。
違いをまとめると以下の表のようになります。

ReactVue3
state の定義useStateref
state の更新set(State の名前)(State の名前).value
click イベントonClick@click
change イベントonChange@change, @input
変数埋め込み{ (変数) }{{ (変数) }}, “(変数)”

React

import React, { useState } from "react"
import "./css/Adder.css"
const Adder = () => {
const [sum, setSum] = useState(0)
const [increase, setIncrease] = useState("1")
const add = () => {
const parsed = parseInt(increase)
if (isNaN(parsed)) {
alert("増加量には数字を入力してください")
} else if (parsed < 0) {
alert("増加量には0以上の値を入力してください")
} else {
setSum(sum + parsed)
}
}
const reset = () => {
setSum(0)
}
const changeIncrease = e => {
const value = e.target.value
const parsed = parseInt(value)
// 空文字か0以上の数字のみ入力可
if (value === "" || (!isNaN(parsed) && parsed >= 0)) {
setIncrease(value)
} else {
alert("0以上の数字を入力してください")
}
}
return (
<div className="adder">
<h2>合計:{sum}</h2>
<p>
増加量:
<input type="number" value={increase} onChange={changeIncrease} />
</p>
<div className="buttons">
<button onClick={add}>足す</button>
<button onClick={reset}>リセット</button>
</div>
</div>
)
}
export default Adder

Vue3

<script setup>
import { ref } from 'vue';
const sum = ref(0);
const increase = ref('1');
const add = () => {
const parsed = parseInt(increase.value);
if (isNaN(parsed)) {
alert('増加量には数字を入力してください');
} else if (parsed < 0) {
alert('増加量には0以上の値を入力してください');
} else {
sum.value += parsed;
}
};
const reset = () => {
sum.value = 0;
};
const changeIncrease = (e) => {
const value = e.target.value;
const parsed = parseInt(value);
// 空文字か0以上の数字のみ入力可
if (value === '' || (!isNaN(parsed) && parsed >= 0)) {
increase.value = value;
} else {
alert('0以上の数字を入力してください');
}
};
</script>
<template>
<div className="adder">
<h2>合計:{{sum}}</h2>
<p>増加量:<input type="number" :value="increase" @input="changeIncrease"/></p>
<div className="buttons">
<button @click="add">足す</button>
<button @click="reset">リセット</button>
</div>
</div>
</template>
<style>
@import './css/Adder.css';
</style>

GitHub Pages へのデプロイ

最後に、GitHub Pages へのデプロイです。
これはどちらも gh-pages を入れることで簡単にデプロイできます。


React
公式のこちらのページを参考にデプロイします。


1.package.json にhomepageを追加する

"homepage": "https://(githubのユーザー名).github.io/sample-app",

2.npm パッケージgh-pagesをインストールし、package.json にscriptsを追加

npm install --save gh-pages

そして、package.json に以下の記述を追加

"scripts": {
+ "predeploy": "npm run build",
+ "deploy": "gh-pages -d build",
"start": "react-scripts start",

3.デプロイコマンドを打つ

npm run deploy

Vue3
こちらのページを参考にしました。


1.vite.config.js にbaseを追加する

export default defineConfig({
+ base: '/sample-app/',
plugins: [vue()],

2.npm パッケージgh-pagesをインストールし、package.json にscriptsを追加

npm install --save gh-pages

そして、package.json に以下の記述を追加

"scripts": {
+ "deploy": "npm run build && gh-pages -d dist",
"start": "react-scripts start",

3.デプロイコマンドを打つ

npm run deploy


まとめ

今回の記事では、Vue3 の最新の書き方を React と比較しながら紹介しました。
比較するとわかるように、細かい部分で名称やコマンドの違いがあるものの、概ね構造が同じであることがわかりました。
このため、Vue3 と React を行き来することはそれほど難しいことではないと思います。


今回は基本的な部分の比較になってしまったので、もし需要があれば詳細な部分についての比較も記事にしたいと思います。