HOCを紹介する一文高階コンポーネント (HOC) とは何ですか? 公式ドキュメントによると、「高階コンポーネントは、React でコンポーネント ロジックを再利用するための高度なテクノロジです。これは React API の一部ではなく、React 自体の構成特性から抽出されたパターンです。具体的には、高階コンポーネントは、コンポーネントをパラメーターとして受け入れ、新しいコンポーネントを返す関数です。」 使用シナリオ類似した機能を持つ複数のコンポーネントのメソッドと反応機能(ライフサイクルにおける副作用など)を HOC に抽出し、カプセル化するコンポーネントを HOC に渡します。最後に、共通メソッドをコンポーネントに渡します。 利点コードを簡潔かつエレガントにし、コード量を減らす HOC (高次コンポーネント) /* HOC (高階コンポーネント): コンポーネントを受け取り、パッケージ化されたコンポーネント (拡張コンポーネント) を返します。 - React APIではありません - デコレータパターンに似たデザインパターンです - ≈ Mixin && > Minxin const ラップされたコンポーネント = 高階コンポーネント (ラップされたコンポーネント); // 例: const Wrapper = withRouter(NavBar); 高階コンポーネントは受信したすべてのプロパティをラップされたコンポーネントに渡します(透過的な伝送) Ref は key と同様です。prop ではないので、そのまま通過することはありません。Ref は外装容器にバインドされます。解決方法は、以下の <<ref の取り扱い>> を参照してください。 * */ コンポーネントをパッケージ化するにはどうすればいいですか? /* コンポーネントをパッケージ化するにはどうすればいいですか? 1 つ目は、通常のパッケージ化エクスポートの場合、package import React from 'react'; です。 './Hoc' から Hoc をインポートします。 クラス Header は React.Component を拡張します { 与える() { <span>{ this.props.count }</span> を返します } }; デフォルトの Hoc(Header) をエクスポートします。 ========== インポート後のパッケージ: './header' からヘッダーをインポートします。 './Hoc' から Hoc をインポートします。 const EnhanceHeader = Hoc(ヘッダー); const ホーム = () => { 戻る ( <div> <EnhanceHeader 数 = {1} /> </div> ) } 2 番目のタイプ: デコレータ パッケージング。クラス コンポーネントでのみ使用できます。import React from 'react'; './Hoc' から Hoc をインポートします。 @ホック デフォルトクラス Header をエクスポートし、React.Component を拡張します { 与える() { <span>{ this.props.count }</span> を返します } }; ======= @ホック クラス Header は React.Component を拡張します { 与える() { <span>{ this.props.count }</span> を返します } }; デフォルトのヘッダーをエクスポートします。 * */ シンプルなHOCの定義 /* コンポーネントを受け取ってコンポーネントを返す単純な HOC を定義します。import React from 'react'; // クラスコンポーネントのエクスポートのデフォルト関数を返す Hoc(WrappedComponent) { /* 戻りクラスは React.Component を拡張します {} - React Developer Toolsに表示される名前はコンポーネントです 戻りクラス Wrapper は React.Component を拡張します {} - React Developer Toolsに表示される名前はWrapperです *\ 戻りクラスはReact.Componentを拡張します{ 与える() { <WrappedComponent {...this.props} /> を返します。 } }; } // 関数コンポーネントを返す export default function Hoc(WrappedComponent) { /* 関数(props)を返す{} - React Developer Toolsに表示される名前はAnonymousです 関数 Wrapper(props) を返します {} - React Developer Toolsに表示される名前はWrapperです *\ 関数 Wrapper(props) を返す { <WrappedComponent {...props} /> を返します。 }; } * */ Hocにパラメータを渡す /* Hoc にパラメータを渡す // Hoc は任意のパラメータを受け入れることができる export default function Hoc(WrappedComponent, title, user, data) { 戻りクラス Wrapper は React.Component を拡張します { 与える() { <WrappedComponent {...this.props} /> を返します。 } }; }; // パッケージ化時にパラメータを渡す const EnhanceHeader = Hoc(Header, 'title', { name: '霖'}, [1, 2, 3]); * */ Hoc ネスト /* Hoc ネスト、関数カリー化の原則 // Hoc1: コンポーネントに title 属性を追加する export default function Hoc1(WrappedComponent, title) { 戻りクラスはReact.Componentを拡張します{ 与える() { <WrappedComponent title={title} {...this.props} /> を返します。 } }; }; // Hoc2: コンポーネントの表示内容を変更する export default function Hoc2(WrappedComponent, content) { return class extends WrappedComponent { // ここでは逆継承が使用されています render() { const elementTree = super.render(); // React は Js オブジェクトを使用して Dom ツリー構造をシミュレートします。Js オブジェクトのプロパティを変更することでデータを操作できます。 console.log(elementTree); // 内部の構造についてよくわからない場合は、印刷できます + 公式 Web サイトの cloneElement() で詳細を確認できます。 const newElementTree = React.cloneElement(elementTree, { children: `Your content has been hijacked: ${content}` }); newElementTree を返します。 } }; }; // ラップされたコンポーネント export default class Header extends React.Component { 与える() { 定数 title = this.props; 戻る ( <span title={title}> デフォルトコンテンツ</span> ) } }; // import Hoc1 from './Hoc1' を使用します。 './Hoc2' から Hoc2 をインポートします。 /* パッケージ化プロセス 1. const Wrapper = Hoc2(Header, 'content'); 2. Hoc1(ラッパー) ** const EnhanceHeader = Hoc1(Hoc2(ヘッダー、'コンテンツ'、'タイトル'); デフォルト関数 Home() をエクスポートします。 戻る ( <div> <EnhanceHeader /> </div> ); }; * */ 参照の処理 /* 参照の処理 例: Hoc1(Hoc2(コンテンツ)) <Content ref={myRef} /> Content にバインドされた ref は Hoc1 にバインドされ、最初のメソッド React.forwardRef には渡されません ================ React.forwardRef()を使用してHoc1の外部でrefを処理し、propsを使用してrefを渡す 0. forwardRefを高階成分の外側にラップし、refをインターセプトして取得し、props(xxx={ref})を追加し、実際の成分はprops.xxxを通じて取得されます1. 使用時にref={XXXX}を渡す // 2番目の方法との違い2. forwardRefの2番目のパラメータを使用してrefを取得します 3. 参照を下方に転送するための新しいプロパティを追加します。例: forwardedRef={ref} 4. 実際のコンポーネントにref={props.forwardedRef}をバインドする const Home = (props) => { 定数 connectRef = useRef(null); 戻る ( <div> <コンテンツref={connectRef} /> </div> ); }; // ラップされたコンポーネント const Content = (props) => { 戻る ( <div> <input type="password" ref={props.forwardedRef} /> </div> ); }; // forwardRef の 2 番目の入力パラメータは ref を受け取り、Hoc の外側のレイヤーで ref を処理できます export default React.forwardRef((props, ref) => { const Wrapper = React.memo(Content); // Hoc // forwardRef は Wrapper をラップします // Wrapper 内の実際のコンポーネントに ref を渡す必要があります // Wrapper に props 属性を追加し、ref オブジェクトを props として子コンポーネントに渡します return <Wrapper {...props} forwardedRef={ref} />; }); 2番目の方法 ========== 0. 使用時に参照を保存するにはpropsを使用します 1. 使用時にxxx={ref}を渡す // 最初の方法との違い 2. 実際のコンポーネントでref={props.xxx}をバインドする const Home = (props) => { 定数 connectRef = useRef(null); 戻る ( <div> <コンテンツ forwardedRef={connectRef} /> </div> ); }; // 高階コンポーネントを定義する export const Hoc = (WrappedComponent) => { クラス Wrapper は React.Component を拡張します { 与える() { <WrappedComponent {...props} /> を返します。 } } } // ラップされたコンポーネント const Content = (props) => { 戻る ( <div> <input type="password" ref={props.forwardedRef} /> </div> ); }; // パッケージ化プロセス export default Hoc(Content); * */ ラップされたコンポーネントの静的メソッドの使用 /* ラップされたコンポーネントの静的メソッドを使用する // ラップされたコンポーネントに静的プロパティとメソッドを追加する export default class Header extends React.Component { 静的 displayName = 'ヘッダー'; 静的 showName = () => { console.log(この表示名); }; 与える() { <span>ヘッダー</span>を返す } }; //HOC デフォルト関数 Hoc(WrappedComponent) をエクスポートします。 戻りクラス Wrapper は React.Component を拡張します { 与える() { <WrappedComponent {...this.props} /> を返します。 } }; }; =========== // Hoc パッケージ化後のコンポーネントは静的メソッドを取得できません import Header from './header'; './Hoc' から Hoc をインポートします。 const EnhanceHeader = Hoc(ヘッダー); デフォルト関数 Home() をエクスポートします。 console.log(EnhanceHeader.displayName); // 未定義 EnhanceHeader.showName(); // 未定義 <EnhanceHeader /> を返す } ============= // 解決策 1: 静的メソッドを HOC にコピーする export default function Hoc(WrappedComponent) { 戻りクラス Wrapper は React.Component を拡張します { static displayName = WrappedComponent.displayName; // ラップされたコンポーネント内の静的メソッドを知る必要があります static showName = WrappedComponent.showName; 与える() { <WrappedComponent {...this.props} /> を返します。 } }; }; ============== // ソリューション 2: すべての静的プロパティとメソッドを自動的にコピーする import React from 'react'; 'hoist-non-react-statics' から hoistNonReactStatic をインポートします。 デフォルト関数 Hoc(WrappedComponent) をエクスポートします。 クラス Wrapper は React.Component を拡張します { 与える() { <WrappedComponent {...this.props} /> を返します。 } }; ホイスト非 React 静的 (ラッパー、ラップされたコンポーネント); ラッパーを返します。 }; ============== // 解決策 3: コンポーネントをエクスポートするときに、追加の静的プロパティとメソッドをインポートする class Header extends React.Component { 与える() { <span>ヘッダー</span>を返す } }; const displayName = 'ヘッダー'; 関数 showName() { console.log(ヘッダーの表示名); }; Header.displayName =displayName; ヘッダー.showName = showName; デフォルトヘッダーをエクスポート エクスポート { displayName, showName } // インポート import Header, { displayName, showName } from './header'; './Hoc' から Hoc をインポートします。 const EnhanceHeader = Hoc(ヘッダー); デフォルト関数 Home() をエクスポートします。 console.log(displayName); // ヘッダー showName(); //ヘッダー <EnhanceHeader /> を返す } * */ ラップされたコンポーネントに渡されたプロパティをインターセプトし、プロパティを追加、削除、変更します。 /* ラップされたコンポーネントに渡されたプロパティをインターセプトし、プロパティを追加、削除、変更します。エクスポートデフォルト関数 Hoc(WrappedComponent) { 戻りクラス Wrapper は React.Component を拡張します { 与える() { // 不要な透過的な転送なしで、現在の Hoc でのみ使用されるいくつかのプロパティをフィルターします。const { forMeProps, forOtherProps } = this.props; // この HOC 内で、ラップされたコンポーネントに注入する必要がある追加のプロパティまたはメソッドを定義します。const injectProps = some-state-or-method; // 通常は状態またはインスタンス メソッドです。// 上位レベルのプロパティと追加のプロパティをラップされたコンポーネントに渡します。 戻る ( <ラップされたコンポーネント injectProps={injectProps} // 注入する必要がある追加のプロパティを渡す {...forOtherProps} // フォローアップに関連するプロパティを渡す /> ) } } } 例えば Hoc は追加のプロパティ 'dealUpper' を受け取ります。true の場合、データを大文字に変換します。dealUpper はこの Hoc でのみ使用されるため、ラップされたコンポーネントに渡す必要はありません // HOC デフォルト関数 Hoc(WrappedComponent) をエクスポートします。 戻りクラス Wrapper は React.Component を拡張します { 与える() { const { dealUpper, ...forOtherProps } = this.props; const {データ} = forOtherProps; if (dealUpper) { オブジェクトに他のプロパティを割り当てます。{data: data.toUpperCase()}) } 戻り値: <WrappedComponent { ...forOtherProps } /> } }; }; // Hoc パッケージ化後に拡張コンポーネントをエクスポートします。import React from 'react'; './Hoc1' から Hoc をインポートします。 クラス Header は React.Component を拡張します { 与える() { console.log(this.props); // { データ: 'ABC' } <span>{this.props.data}</span> を返します } }; export default Hoc(Header); // パッケージ化された拡張コンポーネントをエクスポートします // import Header from './header' を使用してインポートします const ホーム = () => { <Header data={'abc'} dealUpper /> を返します。 } * */ HOCを使用して複雑な共通ロジックを抽出し、さまざまなコンポーネントのさまざまな機能を拡張します。 /* HOC を使用して、複雑な共通ロジックを抽出し、さまざまなコンポーネントのさまざまな機能を拡張します。 import React from 'react'; エクスポートconst Hoc = (WrappedComponent、名前空間) => { クラス Wrapper は React.Component を拡張します { 状態 = { データ: [] } // 同じリクエストメソッドを抽出しました componentDidMount = () => { const { ディスパッチ } = this.props; 急送({ type: `${namespace}/queryData`, // 異なるストアを動的にリクエストする ペイロード: {}, コールバック: res => { もし(res){ this.setState({ データ: res.data }) } } }) } 与える() { 戻り値: <WrappedComponent { ...this.props } data={this.state.data} /> } } } // コンポーネントをパッケージ化import Hoc from './Hoc'; 定数A = ({データ}) => { ... データを返す要求ロジックを省略します (data.map(item => item)); } デフォルトのMyHoc(A, 'a')をエクスポートします。 //パッケージ B コンポーネントimport Hoc from './Hoc'; 定数B = ({データ}) => { ...データ返却要求ロジックを省略( <ul> { data.map((アイテム, インデックス) => { 戻る <li key={index}><{item}/li> } } </ul> ) } デフォルトの Hoc(B, 'b') をエクスポートします。 * */ 制御されていないコンポーネントを制御されたコンポーネントに変える /* 制御されていないコンポーネントを制御されたコンポーネントにする // Hoc コンポーネントのエクスポート デフォルト関数 Hoc(WrappedComponent) { 戻りクラス Wrapper は React.Component を拡張します { 状態 = { 価値: '' }; onChange = (e) => { this.setState({ 値: e.target.value }) }; 与える() { 定数newProps = { 値: this.state.value、 onChange: this.onChange }; <WrappedComponent {...this.props} {...newProps} /> を返します。 } }; }; // 通常のコンポーネントクラス InputComponent は React.Component を拡張します { 与える() { <input {...this.props} /> を返します。 } } // ラップ export default Hoc(InputComponent); * */ 逆継承 /* 逆継承(Hoc でラップされたコンポーネント内の状態とメソッドを使用する) - 逆継承コンポーネントは関数コンポーネントではなくクラスコンポーネントである必要があります export const Hoc = (WrappedComponent) => { class Wrapper extends WrappedComponent { // super ≈ WrappedComponent 内の this 与える() { if (!this.props.data) { 戻り値 <span>読み込み中....</span> } それ以外 { return super.render() //ラップされたコンポーネントのrender()メソッドを呼び出す} } } } ==== デフォルト関数 Hoc(WrappedComponent) をエクスポートします。 戻りクラスはWrappedComponentを拡張します{ 与える() { const elementTree = super.render(); // React は Js オブジェクトを使用して Dom ツリー構造をシミュレートします。Js オブジェクトのプロパティを変更することでデータを操作できます。 console.log(elementTree); // 内部の構造についてよくわからない場合は、印刷できます + 公式 Web サイトの cloneElement() で詳細を確認できます。 const newElementTree = React.cloneElement(elementTree, { children: `Your content has been hijacked` }); newElementTree を返します。 } }; }; * */ レンダリングハイジャック /* レンダリング ハイジャック、例: コンポーネントをレンダリングするかどうかの制御 (グローバル読み込み効果を実行したり、データがない場合に読み込みを表示したりできます...) // 基本的な実装 export const LoadingHoc = (WrappedComponent) => { クラス Wrapper は React.Component を拡張します { 与える() { if (!this.props.data) { 戻り値 <span>読み込み中....</span> } それ以外 { <WrappedComponent {...this.props} /> を返します。 } } } } // 逆継承を使用して実装する export const LoadingHoc = (WrappedComponent) => { class Wrapper extends WrappedComponent { // super ≈ WrappedComponent 内の this 与える() { if (!this.props.data) { 戻り値 <span>読み込み中....</span> } それ以外 { return super.render() //ラップされたコンポーネントのrender()メソッドを呼び出す} } } } ====== 例えば、レンダリングされたコンテンツをハイジャックしてエクスポートするデフォルトの関数 Hoc2(WrappedComponent) { return class extends WrappedComponent { // ここでは逆継承が使用されています render() { const elementTree = super.render(); // React は Js オブジェクトを使用して Dom ツリー構造をシミュレートします。Js オブジェクトのプロパティを変更することでデータを操作できます。 console.log(elementTree); // 内部の構造についてよくわからない場合は、印刷できます + 公式 Web サイトの cloneElement() で詳細を確認できます。 const newElementTree = React.cloneElement(elementTree, { children: `Your content has been hijacked` }); newElementTree を返します。 } }; }; * */ パッケージ名を設定する /* ラッパー名を設定します。デバッグツールReact Developer Toolsで見つけやすくなります。たとえば、高階コンポーネントはHoc、ラップされたコンポーネントはWrappedComponentです。表示される名前はHoc(WrappedComponent)になります。 // クラスコンポーネントのエクスポートのデフォルト関数を返す Hoc(WrappedComponent) { 戻りクラスはReact.Componentを拡張します{ /* static displayName = 'XXX'; は Hoc では定義されていません - React Developer Toolsに表示される名前はAnonymousです static displayName = 'XXX'; はパッケージ化されたコンポーネントで定義されていません - React Developer Toolsに表示される名前は未定義のHocです パッケージ化されたコンポーネントで static displayName = 'header' を定義します。 - React Developer Toolsに表示される名前はheader Hocです *\ 静的 displayName = `Hoc(${WrappedComponent.displayName}); 与える() { <WrappedComponent {...this.props} /> を返します。 } }; } // 関数コンポーネントを返す export default function Hoc(WrappedComponent) { /* 関数(props)を返す{} - React Developer Toolsに表示される名前はAnonymousです 関数 Wrapper(props) を返します {} - React Developer Toolsに表示される名前はWrapperです * 関数 Wrapper(props) を返す { <WrappedComponent {...props} /> を返します。 }; } ======= デフォルト関数 Hoc(WrappedComponent) をエクスポートします。 const ラッパー = (props) => { <WrappedComponent {...props} /> を返します。 }; /* static displayName = 'XXX'; はパッケージ化されたコンポーネントで定義されていません - React Developer Toolsに表示される名前は未定義のHocです パッケージ化されたコンポーネントで static displayName = 'header' を定義します。 - React Developer Toolsに表示される名前はheader Hocです *\ Wrapper.displayName = `Hoc(${WrappedComponent.displayName})`; ラッパーを返します。 } ===== // ラップされたコンポーネント export default class Header extends React.Component { 静的 displayName = 'ヘッダー'; 与える() { <span>{ this.props.count }</span> を返します } }; * */ レンダリングではHOCを使用しない /* レンダリングではHOCを使用しない 例えば デフォルトクラスHomeをエクスポートし、React.Componentを拡張します。 与える() { // 各レンダリングで新しいラッパーが作成されます // ラッパー1 !== ラッパー2 // 上位コンポーネントがアンインストールされ、再マウントされ、状態が失われます (例: チェックボックスの選択が失われる | 状態がクリアされる) × const ラッパー = Hoc(WrappedComponent); <ラッパー /> を返します } } ========= √ const ラッパー = myHoc(WrappedComponent); デフォルトクラスHomeをエクスポートし、React.Componentを拡張します。 与える() { <ラッパー /> を返します } } * */ Hoc レンダリング順序 /* Hoc レンダリング順序 Hoc (ヘッダー) componentDidMount: ヘッダー -> HOC コンポーネントWillUnMount: HOC -> ヘッダー * */ HOCとMixin /* HOCとMixin HOC - 関数型プログラミングの概念に属する - ラップされたコンポーネントは高階コンポーネントの存在を認識できない - 高階コンポーネントによって返されるコンポーネントは、元のベースで拡張されるMixin - ミックスイン モードでは、ラップされたコンポーネントに新しいプロパティとメソッドが継続的に追加されます - ラップされたコンポーネントはそれを認識できます - 処理が必要です (名前の競合、状態の維持) * */ 以上がReact高階コンポーネントHOCの使い方の詳しい内容です。React高階コンポーネントHOCについてさらに詳しく知りたい方は、123WORDPRESS.COMの他の関連記事もぜひご覧ください! 以下もご興味があるかもしれません:
|
<<: MySQLオンラインDDL gh-ostの使用の概要
>>: CentOS 7.6 Telnetサービス構築プロセス(Opensshアップグレードバトル第一弾のバックアップトランスポートライン構築)
背景情報最近、Windows パフォーマンスに関する本を読み直しています。以前は SCOM 監視を使...
一般的な携帯電話のスタイル: @media all および (orientation : 縦向き) ...
序文早速本題に入りましょう。これからお話しするのは次のマインドマップです。まずは印象をつかんでくださ...
httpとhttpsの違いは一部のウェブサイトでは、http を開くと、安全ではないというメッセージ...
ここ数日、ウェブサイトを初めて開いたときにアクセスが非常に遅いのですが、その後はページが正常に開きま...
目次PagodaをインストールするPythonランタイム環境を構成するPythonをインストールする...
序文div またはモジュールに overflow: scroll 属性を使用すると、iOS フォンで...
簡単な説明これは CSS3 のクールな 3D キューブのプリロード効果です。この特殊効果は、シンプル...
<本文> <div id="ルート"> <h2&...
Linux で FTP サーバーを設定するためのチュートリアルを参照してください https://w...
HTML 入力属性値属性value 属性は、入力フィールドの初期値を指定します。 <フォーム...
以前は、Web ページのプリンタ対応バージョンを作成するには、印刷したときに見栄えがよくなるようにレ...
目次序文SSHとは何かssh は何に使用されますか? sshの使い方ssh 再修正要約する序文ssh...
目次序文1. 例で理解する2. ソースコードを分析する3. まとめ要約する序文他の人のコンポーネント...
#!/bin/bash #SVNをダウンロード yum -y サブバージョンをインストールします ...