この記事は「構造パスで作るシンプルなフロントエンドフレームワーク (Structive)」Advent Calendarの1日目です。
Structiveについて詳しくはこちらより
はじめに
現代のフロントエンド開発では、React、Vue、Angularといった強力なフレームワークが広く使われています。しかし、これらのフレームワークを使っていて、こんな疑問を感じたことはありませんか?
- なぜこんなに書くコードが多いのか? ボイラープレートが多く、本質的なロジックよりも「フレームワークのお作法」に時間を取られる
- UIとデータの関係が見えにくい コンポーネント、state、props、hooks...複数の概念を行き来しながら理解する必要がある
- パフォーマンスの仕組みが複雑 仮想DOM、差分検出、メモ化...内部で何が起きているのか理解するのが難しい
これらの課題を、構造パスという一つのシンプルな概念で解決できる可能性があります。今日はその導入として、現状の課題と構造パスのアプローチを紹介します。
従来のフレームワークが抱える課題
1. ボイラープレートの多さ
たとえば、ユーザー名を表示する単純なUIを考えてみましょう。
React の場合:
import { useState } from 'react';
function UserProfile() {
const [user, setUser] = useState({ name: "Alice" });
const handleNameChange = (e) => {
setUser({ ...user, name: e.target.value });
};
return (
<div>
<p>Name: {user.name}</p>
<input value={user.name} onChange={handleNameChange} />
</div>
);
}
このコードには以下のような「フレームワーク固有の記述」が含まれています:
-
useStateのインポートと呼び出し - setter関数(
setUser)の定義 - イベントハンドラ関数の定義
- スプレッド構文を使った不変性の維持
やりたいことは「ユーザー名を表示して編集する」だけなのに、フレームワークの都合でかなりのコードを書く必要があります。
2. UIとデータの関係の複雑さ
従来のフレームワークでは、UIとデータの間に複数の中間層が存在します:
データ → State管理 → Props → Component → 仮想DOM → 実DOM
データを変更したいとき、どの層でどう処理すべきか考える必要があり、認知負荷が高まります。
3. 仮想DOMのオーバーヘッド
多くのフレームワークは仮想DOMを使って効率的な更新を実現していますが、これには以下のコストがかかります:
- 仮想DOMツリーの構築
- 前回の仮想DOMとの差分計算
- 実DOMへのパッチ適用
単純な値の変更でも、このプロセス全体を経由する必要があります。
構造パスというアプローチ
構造パスを使ったフレームワーク(Structive)では、これらの課題を根本的に解決します。
構造パスとは?
構造パスは、データの位置を文字列で表現する「住所」のようなものです:
const user = { name: "Alice", age: 25 };
const products = [
{ name: "Laptop", price: 999 },
{ name: "Mouse", price: 29 }
];
// 構造パス
"user.name" // → "Alice"
"user.age" // → 25
"products.*.name" // → "Laptop" や "Mouse" を表す(ワイルドカード)
"products.*.price" // → 999 や 29 を表す
シンプルなコード例
同じユーザー名表示UIを構造パスで書くと:
構造パス方式:
<template>
<div>
<p>Name: {{ user.name }}</p>
<input data-bind="value: user.name">
</div>
</template>
<script type="module">
export default class {
user = { name: "Alice" };
}
</script>
注目すべきポイント:
- setter関数は不要 - データを直接変更するだけ
-
イベントハンドラは不要 -
data-bindで自動的に双方向バインディング -
UIとデータが同じ構造 -
{{ user.name }}とuser = { name: ... }が対応
なぜシンプルになるのか?
構造パスの核心的なアイデアは:
UIと状態は同じデータの異なる表出である
つまり、UIの{{ user.name }}と状態のuser.nameは、同じ構造パスで結ばれた「一つのもの」です。
この考え方により:
- UIは状態を「描画」するだけ
- 状態の変更は直接オブジェクトを操作するだけ
- フレームワークは構造パスを通じて両者を自動的に同期
中間層が不要になり、コードが劇的にシンプルになります。
仮想DOMを使わないリアクティビティ
構造パスを使うと、状態の変更をピンポイントで検知できます:
// 状態を変更
this["user.name"] = "Bob";
// フレームワークは「user.name」という構造パスが変更されたことを検知
// → そのパスに紐づくUI要素だけを更新
仮想DOM全体を再構築して差分を計算する必要がありません。変更された構造パスに対応するDOM要素だけを直接更新します。
明日以降の予定
この24日間で、構造パスを使ったフレームワークの全体像を学んでいきます:
- Week 1(基礎編): 構造パスの基本概念とシンプルな実装
- Week 2(コア機能編): ループ、条件分岐、イベント処理
- Week 3(応用編): コンポーネント化とスケーラビリティ
- Week 4(実践編): 既存フレームワークとの比較と実戦投入
まとめ
今日は、従来のフレームワークが抱える課題と、構造パスという新しいアプローチを紹介しました。
構造パスの利点:
- ボイラープレートの排除
- UIとデータの直接的な関係
- 仮想DOMなしの効率的な更新
- 学習コストの低減
明日は、構造パスの基本的な仕組みをより詳しく見ていきます。
次回: Day 2「構造パスの基本 - データへの『住所』という考え方」
この記事が面白いと思ったら、ぜひスターやコメントをお願いします!