Remix 3 の新しいコンポーネントライブラリとは何か:Web標準ベースのUIコンポーネント設計を解説

Remix 3 の新しいコンポーネントライブラリとは何か:Web標準ベースのUIコンポーネント設計を解説

組み込みコンポーネントの設計原則

Remix 3 が導入する新しいコンポーネントライブラリは、Web標準に基づいたUI設計を特徴とする。Remixチームは既存のReact用コンポーネント群に依存せず、高品質な組み込みコンポーネント(例: メニューやフォーム)を提供する計画である。これらはアクセシビリティへの配慮が組み込まれた実装であり、CSSプロパティやclass属性といったウェブネイティブの機能を活用している。また、独自のコンポーネントライブラリではカスタムイベントとネイティブDOMイベントを活用し、Reactでは得られないネイティブなイベント伝播も実現されている。リリース当初に提供されるコンポーネントはまだ基本的なものに限られるが、チームは今後機能を拡充していく計画だとされている。

なぜ Remix 3 は独自のコンポーネントモデルに移行したのか:設計背景と目的を詳細に深掘り

React依存からの脱却

Remix 3 は、それまでReactに依存していた従来の設計から脱却するために、新しいコンポーネントモデルを採用する。React生態系はHooksやサーバーコンポーネントなどの複雑化が進み、React RouterやViteなどを経てRemix自体もReact Routerに統合されるなど、従来の枠組みの制約が顕在化していた。Remixチームはこうした制約から離れ、よりシンプルで開発体験の高速化を図るため、独自のコンポーネントモデルを構築した。このモデルでは、Webプラットフォームの機能(Fetch APIやネイティブイベントなど)に直接依存し、フレームワークの魔法を削減して開発の可視性を高めることが目指されている。この結果、Node.js、Deno、Bunなど任意のJavaScript実行環境上でも同一コードが動作可能になるという利点もある。

Reactコンポーネントとの違い・設計思想の徹底比較:宣言型Reactと命令型Remixモデルそれぞれの特徴

宣言型 vs 命令型の違い

Remix 3 のコアとなるレンダリングモデルは、従来のReactの宣言型アプローチとは大きく異なる。Remix 3 はReactをまったく使わず、仮想DOMも存在しない。状態変更は自動ではなく、開発者が明示的に this.update() を呼び出してUIを更新する命令型のモデルとなっている。イベント処理もブラウザのネイティブなカスタムイベントシステムを利用し、Reactの合成イベントではなく標準のonプロパティと @remix-run/events ライブラリを介して取り扱う。これにより、通常のDOMイベントと同じようにイベントが伝播する設計となっている。このように、Remix 3 の命令型モデルは、状態とビューの結合を非常に明示的に扱う点で、宣言型Reactの流れとは根本的に異なる。

基本的なコンポーネントの書き方と構造:閉じ込めた変数と this.update を使った命令型コンポーネントの実装例

基本構造と明示的更新

新しいRemixのコンポーネントは、関数を返す関数という構造をとる。たとえば基本的なカウンターコンポーネントでは export function App(this: Remix.Handle) { let count = 0; … return () => (…) } のように、外側の関数で初期状態を定義し、内側の関数でUIを返す形になる。状態は閉じ込められた変数として管理され、ボタンのイベントハンドラ内などで状態を書き換えた後に this.update() を呼ぶことで再描画をトリガーする。この例では <button on={pressDown(increment)}> のように @remix-run/events が用いられ、アクセシビリティ対応済みの pressDown ハンドラでクリックとキーボード入力を一元的に扱う。こうして、宣言的ではなく明示的な制御でコンポーネントを更新できるようになっている。

状態管理とイベント処理の仕組み(Hooksなしでどう書くか):命令型モデルにおける状態更新とネイティブイベント伝播

ステートとネイティブイベント

状態管理はフックを使わず、純粋なJavaScriptの変数で行う。先の例での let count = 0 のように、状態は通常のクロージャ変数として保持される。そのため状態変更を検知する仕組みはなく、変更後は this.update() 呼び出しが必要になる。イベント処理はReactと異なり、ブラウザ標準のイベントシステムを活用する。要素の属性として on プロパティにリスナを渡し、pressDown や他の組み込みイベントを利用して複数の入力方法(クリック・キー操作など)をまとめて扱う。つまり、ネイティブイベント伝播をベースにしてUI更新を行うため、リアクティブフレームワークの感覚とは違い、明示的に状態更新とイベントハンドリングを書く必要がある。

Web標準APIと連携するコンポーネント設計:ブラウザ機能を最大限に活用するアプローチ

標準APIとの統合

Remix 3 ではWeb標準APIとの連携が徹底されている。ルーティングやデータ処理においては、ブラウザ/サーバ双方で使える Request/Response オブジェクトや URLFormData などのネイティブAPIに直接アクセスする設計になっている。たとえば、コンポーネントのライフサイクル中の非同期処理には AbortSignalthis.signal)が提供され、アンマウント時や再レンダー時にフェッチをキャンセルできる。また、独自のカスタムイベントもブラウザネイティブな仕組みで発行できるため、Webコンポーネントや他ライブラリとの親和性が高い。Remix 3 はその根幹でFetch APIやネイティブイベントを活用し、ビルトインのWeb機能を最大限利用する方向で設計されている。

実装例:Todo/タスク管理アプリを作ってみる – 新コンポーネントAPIを用いた実践ガイド

ToDoアプリの実装例

実際に新しいコンポーネントAPIを使ってToDo管理アプリを作ると、次のようになる。まずタスク一覧や入力値をクロージャ変数で管理し、ユーザーの操作に応じて更新を行う。例えば let todos: string[] = [] としてタスク配列を用意し、<input> 要素の on イベントでユーザー入力を受け取って todos に追加するロジックを書く。操作後は必ず this.update() を呼び出して画面更新をトリガーする。こうした手続き的な記述とWeb標準イベントを組み合わせれば、ReactのようなステートフックがなくてもToDoアプリは構築できる。たとえば<button on={events.click(() => { todos.push(inputValue); this.update(); })}>追加 のように書くことで、ボタン操作時にタスクを追加し、即座にUIが更新される。実際の実装では @remix-run/events パッケージに含まれる events API も利用でき、フォーム送信や入力イベントでも同様の原則で状態更新が可能である。

現時点の制限事項と注意点(SSR・async対応など):開発者が知っておくべき制約と考慮点

制約と開発上の留意点

現時点でRemix 3 はまだ実験的な段階にあり、本番用途には未対応である。コアパッケージの多くはアルファ版で、APIも変更される可能性が高い。命令型モデルへの慣れも必要で、this.update() の手動呼び出しや関数戻り値でのレンダリングなど、学習コストは低くないと指摘されている。SSRや非同期処理も従来のReactとは異なるアプローチとなっている。公式情報によれば、React Server Components のような魔法的な同期処理ではなく、HTML をストリームする <Frame> コンポーネントによる部分的な描画を行う方針で、HTMX/Turbo のような境界ストリーミングを採用するという。このため、開発者は従来のSSR・ハイドレーションの感覚を捨て、明示的なフローで非同期処理を組む必要がある点に注意が必要である。

既存のReact/Remixアプリへの導入戦略:段階的移行と共存のベストプラクティス

移行戦略と共存

既存のReact/Remixアプリへの適用には慎重な戦略が求められる。Remixチーム自身も、新バージョンに移行するかどうかは選択肢であり、React Router v7(Remix 2系相当)の安定ルートを維持しつつ、新フレームワークを試す手もあると案内している。もし移行する場合、既存コンポーネントを新モデルに書き換える必要があり、事実上全体の再構築になる(移行はルーティング定義やコンポーネント単位で段階的に進めるしかない)。一方で、Remix 3 はWebコンポーネントとの相性が良いため、段階的な共存の可能性もある。具体的には、新旧両方の部分を共存させたアーキテクチャや、必要な部分だけをカスタムエレメント化して組み込むといったアプローチが考えられる。プロジェクトの状況に応じて最適なアプローチを判断し、段階的に移行を進めることが望ましい。

資料請求

RELATED POSTS 関連記事