日本語訳タイトルは「フロントエンドのデザインパターン」となっているが、UI設計の話ではなくReact特有のデザインパターンのコードの書き方の説明だ。
日本ではデザインパターンはまだまだWordPressのテーマを使用したり、Bootstrapのようなcssのデザインテンプレートをマッシュアップして使用することが多い。しかし時代はReactのエコシステムの中でUIを形作ることが主流になりつつある。
国内のwebデザイナーやUI/UXデザイナーはReactを使用する事にはまだまだ敷居が高く感じている事だろう。 国内のデザイナーはUXを作る事時にまだまだ使い慣れているjQueryなどのライブラリを使ってしまうことが多い。少しでもReactのエコシステムを理解してもらえるようにこちらの優れた翻訳版「フロントエンドのデザインパターン」を要約して紹介して行こうと思う。
※本家Improve how you architect webappsのリンク
React
過去5年間、NPM(JavaScript 系のパッケージを管理するツール)で最もダウンロードされているJavaScript(ES6)のフレームワークである。Reactの最新バージョンでは、Hooksという機能が導入されアプリケーションの設計において、従来のデザインパターンの多くを置き換えることができる。
シングルトンパターン
一度だけインスタンス化でき、グローバルにアクセスできるクラス。アプリケーションのグローバルな状態を管理するのに適している。
Counterクラスのインスタンスが1つだけ作成されるようにする方法はinstanceという変数を作成しCounterのコンストラクタで新しいインスタンスが作成されるときに、instanceにそのインスタンスへの参照をセットする方法がある。
プロキシパターン
Proxyオブジェクトを使うと、特定のオブジェクトとのやり取りをより自由にコントロールできる。
JavaScriptにはReflectという組み込みオブジェクトがあり、これによりプロキシを扱う際にターゲットオブジェクトを簡単に操作できるようになる。
オブジェクトの振る舞いを制御するための強力な手段であり、プロキシには、バリデーション・書式設定・通知・デバッグなど様々なユースケースがある。パフォーマンスが重要なコードにはプロキシを使用しない。
プロバイダパターン
複数の子コンポーネントからデータを利用できるようにするのにprovider patternが役に立つ。
グローバルなデータの共有に非常に有効で一般的なユースケースとしては、UI テーマに関するステートを多くのコンポーネントで共有することが挙げられる。
ライブラリが組み込みのプロバイダをもつ場合は、そこで提供される値をコンポーネントの中で使用することができる。
プロトタイプパターン
prototype patternは、複数の同じ型のオブジェクトの間でプロパティを共有するために便利な方法。
JavaScriptのネイティブオブジェクトであり、プロトタイプチェーンを通じてオブジェクトからアクセスすることができる。
アプリケーションの中で、同じ型のオブジェクトをたくさん作らなければならないことがよくあります。このような場合に便利なのが、ES6クラスのインスタンスを複数作成する方法だ。
オブジェクトから直接利用できないプロパティにアクセスしようとすると、JavaScript は、__proto__ が指すすべてのオブジェクトを、そのプロパティが見つかるまで再帰的にたどって回る。それがプロトタイプチェーンと呼ばれる理由だ。
コンテナ・プレゼンテーションパターン
このパターンにより、ビューをアプリケーションロジックから分離することができる。React において関心の分離を実現する方法の一つ。
フックを使うと、コンテナ・プレゼンテーションパターンと同じように、コンポーネント内でロジックとビューを簡単に分離することができる。
プレゼンテーションコンポーネントはUIを担当する純粋関数となるのに対し、コンテナコンポーネントはアプリケーションのステートやデータを担当する。
このため、関心の分離を容易に実現することができる。
オブザーバパターン
observer patternにより、あるオブジェクトObserverを別のオブジェクトObservableにSubscribeすることができる。
オブザーバパターンを使用する人気のライブラリにRxJSがある。RxJSには、オブザーバパターンで動作する組み込みの機能や例が数多くある。
モジュールパターン
module patternは、コードを再利用可能な小さな部品へと分割することを可能にする。
再利用可能な小さな部品へとコードを分割できることに加え、モジュールはファイル内の特定の値を非公開にすることも可能とする。
モジュールパターンにより、コードの中で公開してはいけない部分をカプセル化することができる。これにより、意図しない名前の衝突やグローバルスコープの汚染を防ぐことができ、複数の依存関係や名前空間を扱う際に生じるリスクが軽減される。
ミックスインパターン
mixinは、継承をおこなわずに他のオブジェクトやクラスに再利用可能な機能を追加することができるオブジェクトでである。
ミックスインにより継承なしで機能の追加ができ、ミックスイン自身が継承を使うこともできる。
ES6クラスが導入される以前は、React のコンポーネントに機能を追加するためにミックスインがよく使われていた。
Reactチームは、現在はミックスインの使用を推奨していない。ミックスインはコンポーネントを不要に複雑にしがちで、保守や再利用を困難にするため。
メディエータ・ミドルウェアパターン
mediator patternは、中央にあるメディエータという存在を通してコンポーネントどうしがやり取りすることを可能にする。
Express.jsは、Webアプリケーションサーバーのフレームワークとして有名。ユーザーがアクセスするrouteにコールバックを追加することができる。
メディエータパターンは、すべての通信が中央のメディエータを経由して流れるようにすることで、オブジェクト間の多対多の関係を単純化することができる。
HOC パターン
複数のコンポーネントで同じロジックを再利用する方法の1つとしてHOC パターンがある。このパターンにより、アプリケーション全体でコンポーネントロジックを再利用することができる。
HOC パターンを使うと、複数のコンポーネントに同一のロジックを提供し、かつそのロジックを一カ所にまとめておくことができる。
HOCには、受け取るコンポーネントやURLの制限はない。それが有効なコンポーネントで有効なAPIエンドポイントである限り、APIエンドポイントから取得したデータをコンポーネントに受け渡すことだけをおこなう。
レンダープロップパターン
コンポーネントを再利用しやすくするもう一つの方法が、レンダープロップ (render prop) パターン。レンダープロップは、JSXの要素を返す関数を値とするコンポーネントのprop。コンポーネント自身は、レンダープロップ以外のものをレンダリングしない。コンポーネントは、独自のレンダリングロジックを実装する代わりに、単にレンダープロップを呼び出すだけとなる。
Reactのコンポーネントには、通常のJSXコンポーネント以外に、関数を子として渡すことができる。この関数はchildren propを通じて利用することができ、技術的にはrenderプロップと同等だ。
レンダープロップで解決しようとした問題の大部分は、フックによって置き換えられました。再利用性とデータ共有の仕組みをコンポーネントに追加する方法を変えたことで、多くの場合、フックはレンダープロップパターンを置き換えることができるのです。
フックパターン
React16.8では、フック(hook)と呼ばれる新機能が導入された。フックにより、ES2015のクラスコンポーネントを使わずに、Reactのステートやライフサイクルメソッドを利用することができるようになる。
アプリケーションの設計において非常に重要な役割を果たし、従来のデザインパターンの多くは、フックによって置き換えることができる。
クラスコンポーネントを使用する際にReact開発者が遭遇する共通の問題を解決するために、Reactはフックを導入した。フックは、コンポーネントの状態やライフサイクルメソッドを管理するための関数。
フライウェイトパターン
flyweight patternは、類似のオブジェクトを大量に作るときにメモリを節約するための便利な方法。
フライウェイトパターンは、膨大な数のオブジェクトを作成することで、使用可能なRAMをすべて消費してしまうような場合に役に立つ。消費されるメモリの量を最小限に抑えることができる。
JavaScriptではプロトタイプ継承によって、この問題を簡単に解決することができる。現在では、ハードウェアはGB単位のRAM もっているため、フライウェイトパターンの重要性は低くなっている。
ファクトリパターン
factory patternでは、新しいオブジェクトを作成するためにファクトリ関数 (factory function) を使用する。関数がnewキーワードを使わずに新しいオブジェクトを返すとき、その関数はファクトリ関数であるといえる。
ファクトリパターンは、同じプロパティを共有する小さなオブジェクトを複数作成する場合に便利。ファクトリ関数により、現在の環境やユーザー固有の設定に依存するカスタムオブジェクトを返すことができる。
複合パターン
複合コンポーネントパターン (compound component pattern) を使うと、あるタスクを実行するために連携するコンポーネントを作成することができる。
複合パターンは、コンポーネントライブラリを作成するときに便利です。Semantic UIのようなUIライブラリを使うときに、このパターンをよく見かける。
コンポーネントの子要素をマッピングして複合コンポーネントパターンを実装することもできる。
コマンドパターン
コマンドパターン (command pattern) を用いると、あるタスクを実行するオブジェクトと、そのメソッドを呼び出すオブジェクトを切り離すことができことができる。
コマンドパターンにより、ある操作を実行するオブジェクトから、メソッドを切り離すことができる。これは、特定の寿命をもつコマンドや、特定の時間にキューに入れられ実行されるようなコマンドを扱う場合に、より細かな制御を可能とする。
コマンドパターンのユースケースは非常に限られている。また、不要なボイラープレートをアプリケーションに追加してしまうことも少なくない。
ReactのUIのトレンド
少しでもReactで作るUIに興味を持ってもらえたら幸いだ。
ReactでUIを形作るための色々なフレームワークがあるので下記のサイトでUIを見比べてみよう。
Best ReactJS UI Frameworks In 2022