hoc-pattern
認証・ログ・データ取得など、複数のコンポーネントにまたがる横断的な関心事を共有したい場合に使用する、Higher-Order Component(HOC)パターンによるロジック再利用の手法を解説します。
description の原文を見る
Teaches the Higher-Order Component (HOC) pattern for logic reuse. Use when you need to share cross-cutting concerns like authentication, logging, or data fetching across multiple components.
SKILL.md 本文
HOCパターン
目次
アプリケーション内で、複数のコンポーネントで同じロジックを使用したいことがよくあります。このロジックには、コンポーネントへの特定のスタイリングの適用、認可の要求、またはグローバル状態の追加が含まれる可能性があります。
複数のコンポーネント間で同じロジックを再利用する方法の1つは、高階コンポーネント (HOC) パターンを使用することです。このパターンにより、アプリケーション全体でコンポーネントロジックを再利用できます。
使用すべき時
- 同じカスタマイズされていない動作を多くのコンポーネントに適用する必要がある場合に使用します
- コンポーネントがカスタムロジックを追加せずにスタンドアロンで機能する場合に役立ちます
使用すべきでない時
- カスタムフックで同じ結果をより少ないネストとより良い可読性で達成できる場合
- ステートフルロジックの共有に関してフックが慣用的なアプローチであるReact 18+の新しいコードの場合
- HOCラッパーがプロップ名の衝突を引き起こしたり、DevToolsのコンポーネントツリーを不明瞭にする場合
手順
- コンポーネントを受け取り、強化された動作を持つ新しいコンポーネントを返す関数を作成します
- HOCでプロップ名の衝突を避けるため、プロップの名前を変更またはマージします
- ラッパー地獄と深いネストを避けるため、ほとんどの新しいコードではReact Hooksを優先します
- 複数のHOCを注意深く組み合わせ、コンポジションの順序が重要であることに注意してください
詳細
高階コンポーネント (HOC) は、別のコンポーネントを受け取るコンポーネントです。HOCには、パラメータとして渡すコンポーネントに適用したい特定のロジックが含まれています。そのロジックを適用した後、HOCは追加のロジックを持つ要素を返します。
アプリケーション内の複数のコンポーネントに特定のスタイリングを常に追加したいとします。毎回ローカルにstyleオブジェクトを作成する代わりに、渡されたコンポーネントにstyleオブジェクトを追加するHOCを単に作成できます:
function withStyles(Component) {
return props => {
const style = { padding: '0.2rem', margin: '1rem' }
return <Component style={style} {...props} />
}
}
const Button = () => <button>Click me!</button>
const Text = () => <p>Hello World!</p>
const StyledButton = withStyles(Button)
const StyledText = withStyles(Text)
Button と Text コンポーネントの修正版である StyledButton と StyledText コンポーネントを作成しました。どちらもwithStyles HOC で追加されたスタイルを含んでいます!
ユーザー体験を少し改善してみましょう。データをフェッチしている場合、ユーザーに"Loading..."画面を表示したいとします。データをDogImagesコンポーネントに直接追加する代わりに、このロジックを追加してくれるHOCを使用できます。
withLoaderと呼ばれるHOCを作成しましょう。HOCはコンポーネントを受け取り、そのコンポーネントを返す必要があります。この場合、withLoader HOCはデータがフェッチされるまでLoading…を表示する要素を受け取る必要があります。
function withLoader(Element) {
return (props) => <Element />;
}
しかし、受け取った要素を単に返すだけではありません。代わりに、この要素にはデータがまだロード中かどうかを教えてくれるロジックを含める必要があります。
withLoader HOCを非常に再利用可能にするために、Dog API URLをそのコンポーネントにハードコードすることはしません。代わりに、URLをwithLoader HOCの引数として渡すことができるため、このローダーは異なるAPIエンドポイントからデータをフェッチしながらロード表示が必要なコンポーネントで使用できます。
function withLoader(Element, url) {
return (props) => {};
}
HOCは要素を返します。この場合は関数型コンポーネントprops => {}で、データがまだフェッチされている間にLoading…というテキストを表示できるロジックを追加したいです。データがフェッチされると、コンポーネントはフェッチされたデータをプロップとして渡す必要があります。
任意のコンポーネントとURLを受け取ることができるHOCを作成しました。
useEffectフックで、withLoaderHOCはurlの値として渡したAPIエンドポイントからデータをフェッチします。データがまだ返ってきていない間に、Loading...テキストを含む要素を返します。- データがフェッチされると、
dataをフェッチされたデータと同じに設定します。dataがnullではなくなったため、HOCに渡した要素を表示できます!
この動作をアプリケーションに追加するにはどうしたらよいでしょうか? DogImages.jsでは、単にDogImagesコンポーネントをエクスポートしたくありません。代わりに、DogImagesコンポーネントの周囲に"ラップされた"withLoading HOCをエクスポートしたいです。
export default withLoader(
DogImages,
"https://dog.ceo/api/breed/labrador/images/random/6"
);
高階コンポーネントパターンを使用すると、すべてのロジックを1つの場所に保ちながら、同じロジックを複数のコンポーネントに提供できます。withLoader HOCは、受け取るコンポーネントまたはURLについて気にしません。有効なコンポーネントと有効なAPIエンドポイントである限り、渡したコンポーネントにそのAPIエンドポイントからのデータを単に渡します。
組み合わせ
複数の高階コンポーネントを組み合わせることもできます。ユーザーがDogImagesリストの上にホバーしたときにHovering!テキストボックスを表示する機能も追加したいとしましょう。
渡した要素にhoveringプロップを提供するHOCを作成する必要があります。そのプロップに基づいて、ユーザーがDogImagesリストの上にホバーしているかどうかに基づいてテキストボックスを条件付きでレンダリングできます。
これで、withHover HOCをwithLoader HOCの周囲にラップできます。
DogImages要素は、withHoverとwithLoaderの両方から渡したすべてのプロップを含んでいます。hoveringプロップの値がtrueかfalseかに基づいて、Hovering!テキストボックスを条件付きでレンダリングできます。
HOCを組み合わせるために使用される有名なライブラリは recompose です。HOCは大部分がReact Hooksに置き換えられるため、recomposeライブラリはメンテナンスされなくなりました。
フック
場合によっては、HOCパターンをReact Hooksに置き換えることができます。
withHover HOCをuseHoverフックに置き換えてみましょう。高階コンポーネントを持つ代わりに、要素にmouseOverおよびmouseLeaveイベントリスナーを追加するフックをエクスポートします。HOCのように要素を渡すことはできません。代わりに、mouseOverおよびmouseLeaveイベントを取得する必要がありますrefを返します。
useEffectフックはコンポーネントにイベントリスナーを追加し、ユーザーが要素の上に現在ホバーしているかどうかに応じて、hoveringの値をtrueまたはfalseに設定します。refとhoveringの値の両方をフックから返す必要があります。refはmouseOverおよびmouseLeaveイベントを受け取る必要があるコンポーネントにrefを追加するため、hoveringはHovering!テキストボックスを条件付きでレンダリングできるようにするためです。
DogImagesコンポーネントをwithHoverコンポーネントでラップする代わりに、コンポーネント内で直接useHoverフックを使用できます。
一般的に言えば、React Hooksはホックパターンを置き換えません。
"ほとんどの場合、フックで十分であり、ツリーのネストを減らすのに役立ちます。" - React Docs
React docsが教えてくれるように、フックを使用するとコンポーネントツリーの深さを減らすことができます。HOCパターンを使用すると、深くネストされたコンポーネントツリーになりやすくなります。
<withAuth>
<withLayout>
<withLogging>
<Component />
</withLogging>
</withLayout>
</withAuth>
フックをコンポーネントに直接追加することで、コンポーネントをラップする必要がなくなります。
高階コンポーネントを使用すると、すべてのロジックを1つの場所に保ちながら、同じロジックを多くのコンポーネントに提供することが可能になります。フックにより、コンポーネント内からカスタム動作を追加でき、複数のコンポーネントがこの動作に依存する場合、HOCパターンと比較してバグを導入するリスクが潜在的に増加する可能性があります。
HOCの最適なユースケース:
- 同じ、カスタマイズされていない 動作がアプリケーション全体の多くのコンポーネントで使用される必要があります。
- コンポーネントはカスタムロジックを追加せずにスタンドアロンで機能できます。
フックの最適なユースケース:
- 動作をそれを使用する各コンポーネントに対してカスタマイズする必要があります。
- 動作がアプリケーション全体に広がっていません。1つまたは2つのコンポーネントのみが動作を使用します。
- 動作がコンポーネントに多くのプロパティを追加します
ケーススタディ
HOCパターンに依存していた一部のライブラリは、リリース後にフックサポートを追加しました。この良い例は Apollo Client です。
Apollo Clientを使用する1つの方法は、graphql()高階コンポーネントを介することです。graphql() HOCを使用すると、高階コンポーネントでラップされたコンポーネントがクライアントからのデータを利用できるようになります! 現在もgraphql() HOCを使用できますが、それを使用することにはいくつかの欠点があります。
コンポーネントが複数のリゾルバーにアクセスする必要がある場合、複数のgraphql()高階コンポーネントを組み合わせる必要があります。複数のHOCを組み合わせると、データがコンポーネントにどのように渡されるかを理解するのが難しくなる可能性があります。HOCの順序は場合によっては重要になる可能性があり、これはコードをリファクタリングするときに簡単にバグを引き起こす可能性があります。
フックのリリース後、Apolloはフックサポートをapollo Clientライブラリに追加しました。graphql()高階コンポーネントを使用する代わりに、開発者はライブラリが提供するフックを通じてデータに直接アクセスできるようになりました。
useMutationフックを使用することで、コンポーネントにデータを提供するために必要なコード量が減少しました。
ボイラープレートの削減に加えて、複数のリゾルバーのデータをコンポーネントで使用するのもはるかに簡単です。複数の高階コンポーネントを組み合わせる必要がない代わりに、単にコンポーネント内で複数のフックを記述できます。この方法でデータがコンポーネントにどのように渡されるかを知ることは非常に簡単であり、コンポーネントをリファクタリングするか、より小さな部分に分解する場合の開発者体験が向上します。
利点
高階コンポーネントパターンを使用することで、再利用したいロジックをすべて1つの場所に保つことができます。これにより、コードを何度も何度も複製し、毎回新しいバグを導入する可能性があるため、アプリケーション全体にバグを誤って広める危険を減らします。ロジックをすべて1つの場所に保つことで、コードをDRYに保ち、懸念事項の分離を簡単に実施できます。
欠点
HOCが要素に渡すことができるプロップの名前は、名前の衝突を引き起こす可能性があります。
function withStyles(Component) {
return props => {
const style = { padding: '0.2rem', margin: '1rem' }
return <Component style={style} {...props} />
}
}
const Button = () => <button style={{ color: 'red' }}>Click me!</button>
const StyledButton = withStyles(Button)
この場合、withStyles HOCは渡した要素にstyleというプロップを追加します。ただし、Buttonコンポーネントは既にstyleというプロップを持っており、これは上書きされます! HOCがプロップの名前を変更するか、プロップをマージすることで、偶然の名前衝突を処理できるようにしてください。
function withStyles(Component) {
return props => {
const style = {
padding: '0.2rem',
margin: '1rem',
...props.style
}
return <Component style={style} {...props} />
}
}
const Button = () => <button style={{ color: 'red' }}>Click me!</button>
const StyledButton = withStyles(Button)
複数の合成されたHOCが、それらの内部にラップされた要素にプロップを渡す場合、どのHOCがどのプロップを担当しているかを理解するのが難しくなる可能性があります。これはデバッグやアプリケーションの拡張を簡単に行うことを妨げる可能性があります。
ソース
参考文献
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- patternsdev
- リポジトリ
- patternsdev/skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/patternsdev/skills / ライセンス: MIT
関連スキル
hugging-face-trackio
Trackioを使用してMLトレーニング実験を追跡・可視化できます。トレーニング中のメトリクスログ記録(Python API)、トレーニング診断のアラート発火、ログされたメトリクスの取得・分析(CLI)が必要な場合に活用してください。リアルタイムダッシュボード表示、Webhookを使用したアラート、HF Space同期、自動化向けのJSON出力に対応しています。
btc-bottom-model
ビットコインのサイクルタイミングモデルで、加重スコアリングシステムを搭載しています。日次パルス(4指標、32ポイント)とウィークリー構造(9指標、68ポイント)の2カテゴリーにわたる13の指標を追跡し、0~100のマーケットヒートスコアを算出します。ETFフロー、ファンディングレート、ロング/ショート比率、恐怖・貪欲指数、LTH-MVRV、NUPL、SOPR(LTH+STH)、LTH供給率、移動平均倍率(365日MA、200週MA)、週次RSI、出来高トレンドに対応します。市場サイクル全体を通じて買いと売りの両方の推奨を提供します。ビットコインの底値拾い、BTCサイクルポジション、買い時・売り時、オンチェーン指標、MVRV、NUPL、SOPR、LTH動向、ETFの流出入、ファンディングレート、恐怖指数、ビットコインが過熱状態か、マイナーコスト、暗号資産市場のセンチメント、BTCのポジションサイジング、「今ビットコインを買うべきか」「BTCが天井をつけているか」「オンチェーン指標は何を示しているか」といった質問の際にこのスキルを活用します。
protein_solubility_optimization
タンパク質の溶解性最適化 - タンパク質の溶解性を最適化します。タンパク質の特性を計算し、溶解性と親水性を予測し、有効な変異を提案します。タンパク質配列の特性計算、タンパク質機能の予測、親水性計算、ゼロショット配列予測を含むタンパク質エンジニアリング業務に使用できます。3つのSCPサーバーから4つのツールを統合しています。
research-lookup
Parallel Chat APIまたはPerplexity sonar-pro-searchを使用して、最新の研究情報を検索できます。学術論文の検索にも対応しています。クエリは自動的に最適なバックエンドにルーティングされるため、論文の検索、研究データの収集、科学情報の検証に活用できます。
tree-formatting
ggtree(R)またはiTOL(ウェブ)を使用して、系統樹の可視化とフォーマットを行います。系統樹を図として描画する際、ツリーレイアウトの選択、分類学に基づく枝やラベルの色付け、クレードの折りたたみ、サポート値の表示、またはツリーへのオーバーレイ追加が必要な場合に使用してください。系統推定(protein-phylogenyスキルを使用)やドメイン注釈(今後の独立したスキル)には使用しないでください。
querying-indonesian-gov-data
インドネシア政府の50以上のAPIとデータソースに接続できます。BPJPH(ハラール認証)、BOM(食品安全)、OJK(金融適正性)、BPS(統計)、BMKG(気象・地震)、インドネシア中央銀行(為替レート)、IDX(株式)、CKAN公開データポータル、pasal.id(第三者法MCP)に対応しています。インドネシア政府データを活用したアプリ開発、.go.idウェブサイトのスクレイピング、ハラール認証の確認、企業の法的適正性の検証、金融機関ステータスの照会、またはインドネシアMCPサーバーへの接続時に使用できます。CSRF処理、CKAN API使用方法、IP制限回避など、すぐに実行可能なPythonパターンを含んでいます。