リファレンス、フレームループ、シーン制御に関する考察、およびR3Fがフロントエンドの考え方に与える影響について
今回のポートフォリオ制作では、React Three Fiberを使って3D表現を取り入れました。 最初に触る前は、React Three Fiberに対して、どこかで「Reactの書き方でThree.jsを扱える便利なライブラリ」くらいの感覚を持っていました。実際、<mesh> や <ambientLight>、<sphereGeometry> のように、JSXの中で3Dオブジェクトを書けるのは非常に直感的です。 Reactを書いている感覚で、3D空間にオブジェクトを配置できる。 コンポーネントとして分割できる。 propsを渡せる。 見た目だけで言えば、通常のReact開発の延長線上にあるようにも見えます。 しかし、実際にアニメーション、パーティクル、3Dモデル、シーン遷移を作り込んでいくと、その印象は大きく変わりました。 React Three Fiberは、単に通常のReactに3Dレンダリングを追加しただけのものではありません。むしろ、Reactの中にThree.jsのリアルタイム描画の世界を持ち込み、その境界をどう扱うかを考える技術だと感じました。 通常のReact開発では、コンポーネントを分割し、状態をstateやpropsで管理し、UIを宣言的に組み立てていきます。ボタン、フォーム、カード、モーダル、一覧表示、ページレイアウトなどであれば、この考え方は非常に強力です。 状態が変わればUIが変わる。 データが変われば表示が変わる。 コンポーネントごとに責務を分けることで、保守しやすい構造を作ることができる。 これはReactの大きな強みです。 しかし、React Three Fiberでは、この考え方をそのまま持ち込むと、逆に苦しくなる場面がありました。 3D空間では、オブジェクトの位置、回転、スケール、透明度、カメラ、ライト、マテリアル、頂点情報などが毎フレーム変化します。特にアニメーションやパーティクル表現では、1秒間に何十回も値を更新します。 この毎フレームの変化を、すべてReactのstateで管理しようとすると、再レンダリングが多くなりすぎます。また、Reactの状態管理に寄せすぎることで、コードの流れがかえって分かりにくくなることもあります。 ここで重要になるのが、useFrame と ref です。 React Three Fiberでは、useFrame の中で毎フレーム処理を行い、ref を通じてThree.jsのオブジェクトを直接操作する場面が多くあります。 たとえば、オブジェクトを少しずつ回転させる。 カメラの位置を補間する。 パーティクルの座標を更新する。 アニメーションの進行度を内部的に保持する。 モードに応じて動き方を切り替える。 こうした処理は、Reactのstateを細かく更新するよりも、ref やバッファを使って命令的に制御した方が自然な場合があります。 ここが、通常のReact開発との大きな違いでした。 Reactを学んでいると、「状態はReactで管理する」「コンポーネントは小さく分ける」「ロジックは分離する」という考え方が身につきます。それはWebアプリケーション開発ではとても大切です。 ただ、React Three FiberのCanvas内では、それをやりすぎると逆に破綻しやすいと感じました。 綺麗に分けたつもりなのに、アニメーションの流れが追いにくくなる。 状態を外に出したら、逆に更新タイミングが分かりづらくなる。 コンポーネントを細かく分割したら、ref やフレーム更新の関係が複雑になる。 Reactらしく整理したはずなのに、3D表現としては扱いにくくなる。 この感覚は、実際にReact Three Fiberで動くものを作ってみないと分かりにくい部分でした。
今回かなり大きな学びになったのは、Canvasの外側と内側では、設計の考え方を変えた方がよいということです。 Canvasの外側は、通常のReact設計として考えられます。 ページ構成、テキスト、ボタン、カード、ナビゲーション、レイアウト、スクロール制御、表示切り替えなどは、Reactのコンポーネント設計と非常に相性が良いです。propsで必要な情報を渡し、stateでUIの状態を管理し、コンポーネントを責務ごとに分ける。このあたりは、普段のReact開発の延長で整理できます。 一方で、Canvasの内側は少し別物です。 Canvasの中では、DOMではなく3D空間を扱います。そこには、scene、camera、light、mesh、geometry、material、animation loop、buffer、frame updateといった概念があります。 この領域では、ReactのUI設計というよりも、Three.jsやゲームエンジンに近い考え方が必要になります。 特に、useFrame の中で動いている処理は、通常のReactコンポーネントとは性質が違います。Reactの再レンダリングによってUIを更新するのではなく、毎フレームごとにオブジェクトの状態を直接変化させます。 そのため、Canvasの内側で動く処理を無理に通常のReact設計へ寄せすぎると、逆に不自然になることがあります。 今回、自分の中でかなり重要だと感じたルールはこれです。 Canvasの外側はReactとして整理する。 Canvasの内側はThree.js制御として見る。 この切り分けを意識するようになってから、React Three Fiberのコードの見え方が少し変わりました。 すべてを細かく分割すれば良いわけではない。 すべてをstateで管理すれば良いわけでもない。 Reactらしさを守る場所と、Three.js的な制御を受け入れる場所を分ける必要がある。 これは、今回かなり悩んだ末に得た感覚です。 特に、アニメーション制御ではこの考え方が重要でした。 パーティクルをただ表示するだけなら、そこまで難しくありません。しかし、パーティクルを特定の形に集めたり、別の形へ変形させたり、軌道上を流したり、爆発するように散らしたり、複数のモードを切り替えたりしようとすると、一気に難易度が上がります。 ここでは、単に見た目を作るだけではなく、時間の流れをどう管理するかが重要になります。 今どのモードなのか。 モードが切り替わってから何秒経ったのか。 各パーティクルはどこからどこへ移動しているのか。 補間の進行度はどれくらいか。 次の状態へ移る条件は何か。 描画負荷は問題ないか。 こうした情報を、毎フレームの中で扱う必要があります。 このとき、定数や型、純粋な計算関数は外に出した方が整理しやすいです。たとえば、パーティクル数、角度、半径、補間関数、座標計算などは、外部に切り出しても問題ありません。 しかし、useFrame の中で動いている制御、ref で保持しているオブジェクト、バッファ更新、モード遷移、アニメーション進行度の管理などは、無理に剥がしすぎると、逆に読みにくくなることがあります。 React的には、ロジックを分けたくなります。 責務を分けたい。 見通しを良くしたい。 再利用できる形にしたい。 でも、React Three Fiberでは、動いている流れそのものが重要になる場面があります。 処理を分解しすぎると、 「今どのタイミングで何が起きているのか」 「このrefはどこで更新されているのか」 「このバッファはどのモードで書き換わるのか」 「このアニメーション状態はどこから来ているのか」 といったことが追いにくくなります。 つまり、React Three Fiberでは、コードの綺麗さだけでなく、時間軸の見通しも大事になります。 これは、普通のUI開発とは少し違う感覚でした。 UIコンポーネントであれば、表示結果と状態の関係を整理することで見通しが良くなります。しかし、React Three Fiberでは、「時間に沿ってどう変化するか」が中心になります。 そのため、処理を分けることよりも、アニメーションの流れを壊さないことの方が重要になる場面があります。
今回の制作を通して、React Three FiberはReactの知識だけでは扱いきれない技術だと感じました。 もちろん、Reactの理解は必要です。コンポーネント構造、props、hooks、レンダリング、状態管理などの知識は前提になります。 ただ、それだけでは足りません。 React Three Fiberでは、3D空間の考え方が必要になります。座標、回転、スケール、カメラ、ライト、マテリアル、ジオメトリ、レンダリング負荷、フレーム更新、アニメーション補間。こうした要素を同時に考える必要があります。 さらに、Webサイトとして組み込む場合は、3D表現だけを考えていれば良いわけでもありません。 ページ全体のUX。 読み込み速度。 スマートフォンでの負荷。 ノートPCでの発熱。 Canvasの表示タイミング。 他のUIアニメーションとの兼ね合い。 Framer Motionとの役割分担。 ブログやコンテンツ表示とのバランス。 このあたりまで考える必要があります。 3D表現は、見た目としては派手です。しかし、派手にすればするほど、パフォーマンスや保守性との戦いになります。 パーティクルを増やせば迫力は出ます。 モデルを複雑にすれば表現力は上がります。 アニメーションを増やせばサイトに動きが出ます。 でも、その分だけ重くなる。 コードも複雑になる。 バグも追いにくくなる。 デバイスによって体験が変わる。 このバランスを取ることが、React Three Fiberの難しいところであり、同時に一番面白いところだと思いました。 今回、React Three Fiberで悩んだ中で特に印象に残っているのは、設計の正解が普通のReactよりも見えにくいことです。 ReactのUI開発であれば、ある程度は一般的な設計方針があります。 コンポーネントを分ける。 状態を上位に持たせる。 副作用を整理する。 表示用コンポーネントとロジックを分ける。 型を定義する。 もちろんReactでも難しい場面はありますが、考え方の軸は比較的分かりやすいです。 一方で、React Three Fiberでは、ただ分ければ良いわけではありません。 Scene単位では分けた方がいい。 Canvasの外側はReactとして整理した方がいい。 定数や型、純粋な計算処理は外に出した方がいい。 でも、useFrame、ref、buffer、アニメーション状態、モード遷移は、無理に分解しすぎない方がいい場合がある。 このバランスが難しいです。 最初は、Reactの設計ルールに寄せて綺麗に整理しようとしていました。でも、動きが複雑になるほど、それだけでは足りないと感じました。 React Three Fiberでは、コードを静的な構造として見るだけではなく、実行中に何がどう変化しているのかを見る必要があります。 どの値が毎フレーム変わるのか。 どの値はReactの再レンダリングに乗せるべきではないのか。 どの処理はrefで持つべきか。 どの処理は外部関数に出しても安全か。 どの処理はSceneの中に残した方が読みやすいか。 この判断が、普通のReactよりもずっと難しいと感じました。 React Three Fiberは、「Reactで3Dを簡単に書けるライブラリ」というだけではありません。Reactのコンポーネント設計と、Three.jsのリアルタイム描画をどう共存させるかを考える技術です。 通常のReact開発では、state、props、component、renderを中心にUIを組み立てます。しかしReact Three Fiberでは、それに加えて、scene、camera、light、mesh、geometry、material、animation loop、refs、buffer、frame updateといった概念を扱う必要があります。 本当に難しいのは、3Dを表示することそのものよりも、その裏側です。 どう動かすか。 どう制御するか。 どう分けるか。 どう軽くするか。 どうReactの世界とThree.jsの世界を接続するか。 そこに、React Three Fiberの本質があると感じました。 今回のポートフォリオ制作を通して、React Three Fiberは自分にとってかなり大きな学びになりました。単に3D表現を追加しただけではなく、Reactの設計に対する考え方そのものを少し変えてくれた技術でもあります。 React Three Fiberは難しいです。ただ、その難しさの中に、普通のWeb UIだけでは味わえない面白さがあります。 ReactでUIを作るだけではなく、ブラウザの中に動く3D空間を設計する。 その感覚を学べたことが、今回の制作で一番大きな収穫でした。