Zenn
🍣

主要なSPAフレームワークまとめ

2025/03/13に公開

事前知識

SPAとは

Single Page Applicationの略
1つのWebページで動作するアプリケーションのこと
モダンなJSフレームワークを使って開発されることが多い

本記事では、React、Vue、Angularに絞って比較

主要なSPAフレームワーク

表にまとめると、下記の通り

フレームワーク 特徴 学習曲線 市場シェア 状態管理 データフロー
React コンポーネントベース、豊富なエコシステム 中程度 40%くらい Hooks、またはライブラリ 単方向のみ
Vue.js 直感的な構文、段階的に導入可能 低め 25%くらい Composition API + Reactive、またはVuexなどのライブラリ 単方向/双方向
Angular フルスタック機能、TS標準 高め 15%くらい Zone.js 単方向/双方向

以降では、各フレームワークの特徴を簡潔にまとめる

React

VueやAngularと比較すると人気度が高く、エコシステムが豊富な点が特徴

単方向データフロー

Reactでは明示的な状態更新(useState)が必要
VueやAngularは双方向データフローも単方向データフローも実装可能

単方向データフローと双方向データフロー
説明 特徴
単方向データフロー データは一方向にのみ流れる、状態の変更は必ず決められたアクションを通じて行う コード量多、状態管理が明確
双方向データフロー データとUIが自動的に同期、状態の変更が双方向に伝播 コード量少、直感的な実装
function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}

豊富なエコシステム

  • Redux/MobX (状態管理)
  • React Router(ルーティング管理)
  • Next.js/Remix(フレームワーク)
  • React Native(ネイティブアプリ用)
  • Material-UI/Chakra UI(コンポーネント)

Vue.js

Reactと同様に、仮想DOMと状態管理の仕組みあり
部分的に導入可能などの柔軟性が強み、学習コストも低い

レンダリングシステム

  • テンプレート構文とJSXの両方をサポート
  • テンプレート構文とJSXの共存も可能

テンプレート構文:HTMLライクで直感的

<template>
  <div>
    <!-- データバインディング -->
    <h1>{{ title }}</h1>
    
    <!-- ディレクティブ -->
    <ul>
      <li v-for="item in items" :key="item.id">
        {{ item.name }}
      </li>
    </ul>
    
    <!-- イベントハンドリング -->
    <button @click="handleClick">Click me</button>
  </div>
</template>

JSX:JSの柔軟性を活かした記述が可能

<script>
export default {
  render() {
    return (
      <div>
        <h1>{this.title}</h1>
        <ul>
          {this.items.map(item => (
            <li key={item.id}>{item.name}</li>
          ))}
        </ul>
        <button onClick={this.handleClick}>Click me</button>
      </div>
    )
  }
}
</script>

ディレクティブシステム

DOM要素に特別な動作を付与するための強力な機能

  1. データバインディング系
<template>
  <!-- テキストバインディング -->
  <span>{{ message }}</span>
  
  <!-- 属性バインディング -->
  <img :src="imageUrl">
  
  <!-- クラスバインディング -->
  <div :class="{ active: isActive }">
</template>
  1. 条件分岐とループ
<template>
  <!-- 条件分岐 -->
  <div v-if="isAdmin">管理者メニュー</div>
  <div v-else-if="isUser">ユーザーメニュー</div>
  <div v-else>ゲストメニュー</div>

  <!-- ループ処理 -->
  <ul>
    <li v-for="item in items" :key="item.id">
      {{ item.name }}
    </li>
  </ul>
</template>

3.イベント処理

<template>
  <!-- 基本的なイベント -->
  <button @click="handleClick">クリック</button>
  
  <!-- イベント修飾子 -->
  <form @submit.prevent="onSubmit">
    <input @keyup.enter="onEnter">
  </form>
</template>
  1. フォーム制御
<template>
  <!-- 双方向バインディング -->
  <input v-model="username">
  
  <!-- 修飾子付き -->
  <input v-model.trim="email">
  <input v-model.number="age">
</template>

カスタムディレクティブ

DOM要素に対して独自の振る舞いを追加できる強力な機能

app.directive('my-directive', {
  // フック関数
  mounted(el, binding) {
    // 要素がDOMに挿入された時の処理
  },
  updated(el, binding) {
    // コンポーネントが更新された時の処理
  }
})

ミックスイン機能

コンポーネント間で再利用可能なロジックを共有する機能

基本的なミックスイン

export const loggerMixin = {
  created() {
    console.log('コンポーネントが作成されました')
  },
  methods: {
    log(message) {
      console.log(message)
    }
  }
}

ミックスイン使用例

<script>
import { loggerMixin } from '../mixins/loggerMixin'

export default {
  mixins: [loggerMixin],
  methods: {
    fetchUsers() {
      this.log('ユーザー取得開始')
      // ユーザー取得処理
    }
  }
}
</script>

Angular

Angular.jsは古い名称なので最新のものはAngular
大規模チーム向け、学習コストは高いが堅牢性の高いシステムにしたい場合に最適

依存性注入(DI)システム

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root',
})
export class DataService {
  constructor(private http: HttpClient) { }

  fetchData() {
    return this.http.get('https://api.example.com/data');
  }
}

RxJSの完全統合

  • RxJSとは
    • 非同期操作やイベントの処理などリアクティブプログラミングを実現するためのライブラリ
export class DataComponent {
  data$ = this.http.get('/api/data').pipe(
    map(response => response.data),
    catchError(error => of([])),
    shareReplay(1)
  );

  constructor(private http: HttpClient) {}
}

AOTコンパイル

  • AOTコンパイル
    • (Ahead-of-Time)コンパイルのこと
    • アプリケーションを実行する前にコンパイルすること
ng build --prod

モジュールシステム

アプリケーションを論理的な単位に分割して整理する仕組み

下記の種類が存在する

  • ルートモジュール
    • アプリケーションの起点
  • 機能モジュール
    • 特定の機能をカプセル化
  • 共有モジュール
    • 再利用可能なコンポーネント
  • コアモジュール
    • シングルトンサービス
  • ルーティングモジュール
    • ナビゲーション制御
@NgModule({
  declarations: [FeatureComponent],
  imports: [
    CommonModule,
    FeatureRoutingModule
  ],
  providers: [FeatureService]
})
export class FeatureModule { }

フォーム処理システム

リアクティブフォームテンプレート駆動フォームの2種類ある
バリデーションなど複雑なフォームにも対応可能

export class UserFormComponent {
  userForm = this.fb.group({
    name: ['', [Validators.required]],
    email: ['', [Validators.email]],
    age: [null, [Validators.min(0)]]
  });

  constructor(private fb: FormBuilder) {}
}

ゾーン(Zone.js)

Angularアプリの変更検知を自動的に行う
非同期処理の監視変更検知のトリガーなど

@Component({
  selector: 'app-example',
  template: `
    <div>{{ data }}</div>
    <button (click)="updateData()">Update</button>
  `
})
export class ExampleComponent {
  data = 'initial';

  updateData() {
    // この変更は自動的に検知される
    this.data = 'updated';
  }
}

Discussion

ログインするとコメントできます