エンジニア1年生によるVueとReactの比較：基本構文・コンポーネント編

:::note warn 
注意

- 2025/03 時点での比較です
- ~~初めて記事を書くので、マークダウン記法で遊んでます~~
:::

# 背景
入社してもうすぐ1年が経ち、この1年でVue.js、React両方に触れてきました。
そこで、知識の整理も兼ねて記事としてアウトプットすることにしました。

※全体比較を一記事にまとめるほどの構成力は持っていないので、概念・機能単位で比較記事を作成していく予定です。

# 自己紹介
初めに、自己紹介をしておこうと思います！
- エンジニアもうすぐ一年（新卒入社、研修3ヶ月・開発業務9ヶ月）
- 業務ではフロントエンド開発（Vue.js）
- 社内の勉強会などで他技術にも触れている
- それぞれの使用歴
  - Vue.js：1年（業務）
  - React：半年（社内勉強会）
- ~~立ち位置はVue寄り（好み）~~

という感じで、フロントエンドエンジニア1年生です:school_satchel:　

# 簡単比較
始めに、書き方や機能など基本的な部分を簡単に比較してみました。
|項目 |Vue.js |React |
|---|---|---|
| 書き方（テンプレート） |HTMLライクで直感的な構文 (.vue)|JSX/TSX |
| コンポーネント |単一ファイルコンポーネント（SFC) |JavaScript/TypeScript関数 |
| データバインディング |双方向データバインディング |単方向データバインディング |　
| 状態管理[^1] |ref, reactive （Pinia, Vuex） |useState（Redux, Zustand） |
| ライフサイクル管理 |ライフサイクルフック（onMounted, updated など） |useEffect |
| スタイリング |Scoped CSSや外部CSS |CSS-in-JSや外部CSS |
| 学習コスト  |低～中（テンプレート構文が直感的で学習しやすい） |中～高（JSXや状態管理の学習が必要） |


※公式ドキュメントに準拠しているつもりですが、分かりやすさ・自分の理解を文章にするなどを優先しているため、ツッコミどころが多いかもしれません。

https://ja.vuejs.org/guide/introduction.html

https://ja.react.dev/learn


# コンポーネントとは？
Vue.jsとReactに共通する重要な概念で、ユーザーインターフェース（UI）を構成する「再利用可能な部品:gear:」を指します。

例えば、ボタン:record_button:や入力フォーム:pencil:などの最小単位コンポーネント、それらを組み合わせた登録画面コンポーネントのようなイメージです。この関係は、子コンポーネントと親コンポーネントと言います。


### コンポーネント設計のメリット・デメリット
コンポーネントを意識した設計は、以下のメリットとデメリットがあります。

メリット
  - 再利用可能
  - コンポーネント単位で設計、開発、テストができる（保守性の向上）
  - コードが整理され、可読性が高い
  - ~~綺麗にコンポーネント分割すると気持ちいい~~


デメリット
  - 再利用性を考慮した初期設計コストが高い
  - 大規模になると、親子の依存関係が複雑になりやすい


# 基本構文・コンポーネントの比較
やっと本編です:sweat_smile:

このセクションでは、VueとReactそれぞれの基本的な書き方とコンポーネントの単位・呼び出し方について説明します

## Vue.js
### 基本構文
Vueでは、テンプレート（HTML）、ロジック（JavaScript）、スタイル（CSS）を1ファイルに統合した形で記述するのが基本です。

コードを用いた説明の方が理解しやすいため、以下にサンプルコードを示します。

```ChildComponent.vue
<template>
  <p>{{ message }}</p>
</template>

<script setup>
const message = "Hello, world"
</script>

<style scoped>
p {
  color: blue;
}
</style>
```
**説明：**
コードから分かる通り、HTMLライクに記述できます。アプリケーション画面とそれぞれのブロックの関係は以下の通りです。
- **templete**
  - アプリケーション画面の大まかな「見た目」を定義します
  - ユーザーが目にする、テキストやボタンなどの要素をここに記述します
- **script**
  - アプリケーション画面の「振る舞い」を定義します
  - イベント処理、データの管理、API呼び出しなど、画面がどのように動作するかをここに記述します
- **style**
  - アプリケーション画面の細かいデザインを定義します
  - templateブロックの要素に対して、配置や色、フォントなどのスタイルを指定します


:::note
補足として、scriptブロックの書き方は**Composition API**と言います。
ここの記述には2通りのAPIスタイルがあり、**Option API**という書き方もあります。


<details><summary>Option APIで書き換えたscript</summary>

``` .vue
<script>
export default {
  data() {
    return {
      message: "Hello, world"
    };
  }
};
</script>
```

</details>
:::

### コンポーネント
基本構文で説明したコード全体が入った`.vue`ファイルが一つのコンポーネントです。これを**単一ファイルコンポーネント（SFC）** と呼びます。

先ほどのコードをコンポーネントとして呼び出すコードは、以下になります。
```ParentComponent.vue
<template>
  <div>
    <h1>親コンポーネント</h1>
    <ChildComponent />
  </div>
</template>

<script setup>
import ChildComponent from './ChildComponent.vue';
</script>
```
<details><summary>ChildComponent.vue</summary>

```ChildComponent.vue
<template>
  <p>{{ message }}</p>
</template>

<script setup>
const message = "Hello, world";
</script>

<style scoped>
p {
  color: blue;
}
</style>
```
</details>

**説明：**
正直見たままで、親コンポーネント側scriptブロックで、子コンポーネントをインポートして、templeteブロックで使用しています。

これで子コンポーネントが呼び出され、そのtempleteブロックが表示されます。

## React
### 基本構文
Reactでは、JSX（JavaScript XML）という形式で、JavaScriptコード内にHTMLを書くスタイルが基本です[^2]。

こちらもコードでの説明の方が理解しやすいため、以下にサンプルコードを示します。

```child.jsx
export default function ChildComponent() {
  const message = "Hello, world";
  return <p style={{ color: "blue" }}>{message}</p>;
}

```
**説明：**
このコードは、非常にJavaScriptライクです。return内にHTML/CSS（見た目）を記述し、関数内のreturn以前の部分にアプリケーションの動作（振る舞い）を記述しています。

:::note
補足として、コンポーネントの書き方は`function`（関数宣言）と**アロー関数** の２つのスタイルがあります。
この記事は、公式ドキュメントに準拠して`function`で記述しています。

<details><summary>アロー関数</summary>

```child.jsx
const ChildComponent = () => {
  const message = "Hello, world";
  return <p style={{ color: "blue" }}>{message}</p>;
};
export default ChildComponent;
```
</details>
:::

### コンポーネント
基本構文で示したJavaScript関数が1つのコンポーネントです。普通のJavaScriptとの違いは以下です。
- 関数名の最初は必ず大文字
- JSX マークアップを`return`する

コンポーネントを呼び出すコードは、以下になります。
```parent.jsx
import ChildComponent from "./child";

export default function ParentComponent() {
  return (
    <div>
      <h1>親コンポーネント</h1>
      <ChildComponent />
    </div>
  );
}
```
**説明：**
親コンポーネント側ファイルで、子コンポーネントをインポートして、親コンポーネントのreturn内のJSX マークアップで使用しています。

これで子コンポーネントが呼び出され、表示されます。

:::note 
同じファイル内で定義している場合は、そのまま使用できます。
<details><summary>同一ファイルで定義</summary>

```family.jsx
function ChildComponent() {
  const message = "Hello, world";
  return <p style={{ color: "blue" }}>{message}</p>;
}

export default function ParentComponent() {
  return (
    <div>
      <h1>親コンポーネント</h1>
      <ChildComponent />
    </div>
  );
}
```
</details>

:::

# まとめ
書くのが楽なので箇条書き
- 普段触るのが、「Nuxt(Composition API) × TypeScript」「Next.js × TSX」なので、元々のVue、Reactとはそこそこ違って比較が結構大変だった
- 初めて記事を書いたので色々手探りだったが、知識整理・説明のために公式ドキュメントを読む、マークダウン記法で遊ぶなど、いい経験になった気がする

# 参考にした記事
基本公式ドキュメントに準拠で、比較記事のイメージの参考にしました。

https://zenn.dev/marokanatani/articles/compare_vue_and_react

https://qiita.com/cypher256/items/8d6c25e3466e4815b3c7

[^1]: 実際に状態管理を行う場合、括弧内の外部ライブラリ、Nuxt（Vueフレームワーク）のuseStateなどを標準機能以上の状態管理を求められることが多いです。
[^2]: TSX（TypeScript XML）という形式もあり、型付けできるのでこっちの方が安全なコードになります。