Higher Order Components (HOC) は、アプリケーション全体でロジックを再利用するのに役立つ React コンポーネントの一種です。用語は複雑に聞こえるかもしれませんが、HOC は理解しやすく、コードベースの保守が簡単になります。
上位コンポーネントは 常に、追加機能を持つ子コンポーネントをラップします。 HOC は、コンポーネントをパラメータとして受け取る関数として定義されます。次に、新しいコンポーネントを返します。これは通常、追加の小道具でラップされた入力コンポーネントをレンダリングします。
簡単な例
HOC が理にかなっているかどうかを理解する最良の方法は、実際に HOC が動作しているのを見ることです。ユーザーのバスケットの状態がアプリケーション内で集中的に保存される、単純なチェックアウト システムを考えてみましょう。この例では Redux を状態ストアとして示していますが、これは説明のみを目的としています。
このオブジェクトがアプリの状態を表すと仮定します。
{
チェックアウト: {
アイテム: [
{
ラベル: 「製品 1」、
価格: 150.00、
数量: 2
}、
{
ラベル: 「製品 2」、
価格: 75.00、
数量: 1
}
】
}
}
ユーザーのバスケット内の商品を表す単純な配列があります。チェックアウト コンポーネントは、注文総額や適用される税金など、この状態から追加の値を取得します。
私たちのチェックアウト システムはおそらく、複数の独立したコンポーネント内の合計値を表示する必要があるでしょう。バスケットを表示するサイドバー ウィジェット、チェックアウト後のレビュー画面、送料計算ツールが表示される場合があります。単純にチェックアウト項目を小道具として渡す単純なシステムでは、ロジックが重複する危険性があります。各コンポーネントはそれ自体で合計注文額を計算する必要があります。
HOC の紹介
HOC がどのように役立つかを見てみましょう。
「反応」から React をインポートします。
“react-redux” から {connect} をインポートします。
const withCheckout = ComponentToWrap => {
const ComponentWithCheckout = クラスは React.Component を拡張します {
与える() {
戻る (
<ComponentToWrap
checkoutItems={this.props.checkout.items}
checkoutTotal={this.total}
{…this.props} />
);
}
合計を取得() {
const 価格 = this.props.checkout.items.map(i => (i.quantity * i.price));
価格を返す.reduce((a, b) => (a + b), 0);
}
}
return connect(({checkout}) => ({checkout}))(ComponentWithCheckout);
}
Checkout でデフォルトをエクスポートします。
ファイルは単一の関数をエクスポートします。
withCheckout
、これは React コンポーネントを唯一のパラメータとして受け取ります (
ComponentToWrap
)。関数内で、それ自体が React コンポーネントである新しい匿名クラスを作成します。
この新しいコンポーネントの
render
メソッドは、のインスタンスを作成します
ComponentToWrap
関数に渡しました。ここで、インスタンスのプロパティを定義することができます。チェックアウト項目の配列を次のように転送します。
checkoutItems
事前に計算された合計値を次のように利用可能にします。
checkoutTotal
。
HOC に渡されたすべての props は内部コンポーネントに転送され、必要なすべてのデータを確実に受信します。この関数は、アプリケーション全体でレンダリングできる状態になっている新しく作成された匿名クラスを返します。
私たちが使用するのは、
connect
の方法
react-redux
それで、
checkout
HOC 内の prop は、
checkout
Redux ストアの状態のキー。これは実装の詳細です。HOC は独自の状態を維持したり、アプリケーション内の他のサービスにアクセスしたりする場合があります。
HOC の使用
今度は HOC を使用します。
「反応」から React をインポートします。
withCheckout を「./withCheckout.js」からインポートします。
class CheckoutReviewScreen extends React.Component {
与える() {
戻る (
<h1>チェックアウト</h1>
<h2>{this.props.checkoutTotal}</h2>
);
}
}
デフォルトを withCheckout(CheckoutReviewScreen) でエクスポートします。
私たちは、
withCheckout
HOC の保存場所
withCheckout .js
新しいチェックアウトレビュー画面コンポーネントと同じディレクトリにあります。コンポーネントをラップすることで、
withCheckout
HOC では、合計注文金額にアクセスして表示できます。自分で計算したり、アプリの状態に保存したりする必要はありません。合計の計算方法を更新したい場合 (固定手数料を追加するなど)、HOC 内の 1 か所で変更を行うだけで済みます。
レンダリングできるようになりました
<チェックアウトレビュー画面 />アプリ内のどこにでも。ラップされたサンプルは、Redux ストアからデータを取得するため、小道具を渡す必要はありません。包まれているので、
withCheckout
、それ自体が Redux でラップされています
connect
、レビュー画面は自動的に
checkoutTotal
アプリの状態にあるすべてのアイテムの価格を合計する prop。
ここで、HOC にどのように名前を付けたかについて言及する価値があります。
withCheckout
。慣例により、HOC 名には通常、
with
ラップするコンポーネントに何かを追加するためです。私たちの場合、HOC はチェックアウト バスケットへの便利なアクセスを提供します。そうでなければ、各コンポーネント内に実装する必要があります。
HOC の利点
HOC を使用すると、コンポーネントから一般的な動作を抽象化し、コードの重複を最小限に抑え、保守性を高めることができます。 HOC により、依存性注入の形式が可能になります。これらは、外部からより多くのものを渡すことができるようにすることで、コンポーネントをよりシンプルに保つのに役立ちます。
HOC は React エコシステム内で一般的です。実際、この記事内でそのような例を確認しました –
connect()
、 一部の
react-redux
、コンポーネントを Redux 状態の変更にサブスクライブします。
HOC は、コンポーネントの自己包含性を壊さずにコードを再利用する方法を提供するため、人気があります。このパターンでは React の構成機能を利用して、副作用のリスクなしに追加の機能を追加できます。
アプリ内の任意のコンポーネントを渡すことができます
withCheckout
何も壊すことなく、HOC はいくつかの追加の小道具を取り付けるだけです。これが、HOC が受け取ったすべての props を転送することが非常に重要である理由です (
{... this .props}
この例では)。ラップされたコンポーネントの通常の動作を妨げる可能性のあることを行ってはなりません。
コンポーネントが HOC に依存しているように感じるかもしれません。そうではないのです。ラップされていないコンポーネントの 2 番目のバージョンをエクスポートして、消費者がどちらを使用するかを選択できるようにすることもできます。
あなたのコンポーネントは実際には特定の小道具を受け取ることだけを要求します –
checkoutTotal
私たちの場合には。これは、HOC によって、またはコンポーネントがレンダリングされる場所に値を渡すことによって提供できます。 HOC により開発は簡素化されますが、レンダリングされるコンポーネントの性質は根本的には変わりません。





