ホームページ > 記事 > ウェブフロントエンド > React の高次コンポーネントの分析例
この記事では主に React の高次コンポーネントについて詳しく説明します。React の高次コンポーネントについてより明確に理解していただければ幸いです。
1. React では、高次コンポーネント (HOC) はコンポーネント ロジックを再利用するための高度なテクノロジです。 HOC は React API の一部ではありません。 HOC は、コンポーネントを取得して新しいコンポーネントを返す関数です。 React では、コンポーネントはコード再利用の基本単位です。
2. HOC を説明するために、次の 2 つの例を取り上げます。
CommentList コンポーネントはコメント リストをレンダリングし、リスト内のデータは外部ソースから取得されます。
class CommentList extends React.Component { constructor() { super(); this.handleChange = this.handleChange.bind(this); this.state = { // "DataSource" is some global data source comments: DataSource.getComments() }; } componentDidMount() { // Subscribe to changes DataSource.addChangeListener(this.handleChange); } componentWillUnmount() { // Clean up listener DataSource.removeChangeListener(this.handleChange); } handleChange() { // Update component state whenever the data source changes this.setState({ comments: DataSource.getComments() }); } render() { return ( <p> {this.state.comments.map((comment) => ( <Comment comment={comment} key={comment.id} /> ))} </p> ); } }
次は、ブログ情報を表示するために使用される BlogPost コンポーネントです
class BlogPost extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.state = { blogPost: DataSource.getBlogPost(props.id) }; } componentDidMount() { DataSource.addChangeListener(this.handleChange); } componentWillUnmount() { DataSource.removeChangeListener(this.handleChange); } handleChange() { this.setState({ blogPost: DataSource.getBlogPost(this.props.id) }); } render() { return <TextBlock text={this.state.blogPost} />; } }
2 つのコンポーネントは異なり、DataSource の異なるメソッドを呼び出し、出力も異なりますが、それらの間の実装はほとんど同じです:
1. 読み込みが完了したら、DataSource に変更リスナーを追加します
2. データソースが変更された場合、リスナー内で setState を呼び出します
3. アンインストール後、変更リスナーを削除します
アプリケーションでは、DataSource にアクセスして setState を呼び出すという同じパターンが何度も発生します。このプロセスを抽象化して、このロジックを 1 か所でのみ定義し、複数のコンポーネント間で共有できるようにしたいと考えています。
次に、コンポーネントを作成する関数を作成します。この関数は 2 つのパラメーターを受け取ります。1 つはコンポーネントで、もう 1 つは関数です。 withSubscription 関数は以下で呼び出されます
const CommentListWithSubscription = withSubscription( CommentList, (DataSource) => DataSource.getComments() ); const BlogPostWithSubscription = withSubscription( BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id) );
withSubscription を呼び出すときに渡される最初のパラメーターはラップされたコンポーネントで、2 番目のパラメーターはデータを取得するために使用される関数です。
CommentListWithSubscription と BlogPostWithSubscription がレンダリングされるとき、CommentList と BlogPost は、DataSource から現在取得されているデータを保存する data と呼ばれる prop を受け入れます。 withSubscription コードは次のとおりです:
// This function takes a component... function withSubscription(WrappedComponent, selectData) { // ...and returns another component... return class extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.state = { data: selectData(DataSource, props) }; } componentDidMount() { // ... that takes care of the subscription... DataSource.addChangeListener(this.handleChange); } componentWillUnmount() { DataSource.removeChangeListener(this.handleChange); } handleChange() { this.setState({ data: selectData(DataSource, this.props) }); } render() { // ... and renders the wrapped component with the fresh data! // Notice that we pass through any additional props return <WrappedComponent data={this.state.data} {...this.props} />; } }; }
HOC は入力コンポーネントを変更せず、その動作を再利用するために継承を使用しません。 HOC は単なる関数です。ラップされたコンポーネントは、コンテナーのすべての props を受け入れます。また、ラップされたコンポーネントの出力をレンダリングするために使用される新しい props (データ) も受け入れます。 HOC はデータがどのように使用されるか、データが使用される理由を気にしません。また、ラップされたコンポーネントはデータがどこで取得されるかを気にしません。
withSubscription は単なる通常の関数であるため、パラメーターはいくつでも追加できます。たとえば、データ プロップの名前を構成可能にして、ラップされたコンポーネントから HOC をさらに分離することができます。
構成 shouldComponentUpdate を受け入れるか、データ ソースのパラメーターを構成します
上位コンポーネントを使用するときに注意する必要があることがいくつかあります。
1. 元のコンポーネントを変更しないでください。これは非常に重要です
以下の例があります:
function logProps(InputComponent) { InputComponent.prototype.componentWillReceiveProps = function(nextProps) { console.log('Current props: ', this.props); console.log('Next props: ', nextProps); }; // The fact that we're returning the original input is a hint that it has // been mutated. return InputComponent; } // EnhancedComponent will log whenever props are received const EnhancedComponent = logProps(InputComponent);
ここにはいくつかの問題があります。 1. インポートされたコンポーネントは、拡張コンポーネントとは別に再利用できません。 2. EnhancedComponent に他の HOC を適用すると、componentWillReceiveProps も変更されます。
関数型コンポーネントにはライフサイクルがないため、この HOC は関数型コンポーネントには適用できません。関数 HOC は、入力コンポーネントをコンテナー コンポーネントにラップすることにより、変更ではなく合成を使用する必要があります。
function logProps(WrappedComponent) { return class extends React.Component { componentWillReceiveProps(nextProps) { console.log('Current props: ', this.props); console.log('Next props: ', nextProps); } render() { // Wraps the input component in a container, without mutating it. Good! return <WrappedComponent {...this.props} />; } } }
この新しい logProps は古い logProps と同じ機能を持ちますが、新しい logProps は潜在的な競合を回避します。クラス型コンポーネントや関数型コンポーネントも同様です。
2. render メソッドで HOC を使用しないでください
React の差分アルゴリズムは、コンポーネントの ID を使用して、レンダーから返された場合に既存のサブツリーを更新するか、古いサブツリーを破棄して新しいサブツリーをロードするかを決定します。メソッド コンポーネントが以前にレンダリングされたコンポーネントと同一 (===) の場合、React は diff アルゴリズムを通じて以前にレンダリングされたコンポーネントを更新します。そうでない場合、以前にレンダリングされたサブツリーは完全にアンロードされます。
render() { // A new version of EnhancedComponent is created on every render // EnhancedComponent1 !== EnhancedComponent2 const EnhancedComponent = enhance(MyComponent); // That causes the entire subtree to unmount/remount each time! return <EnhancedComponent />; }
結果のコンポーネントが 1 回だけ作成されるように、コンポーネント定義の外で HOC を使用します。場合によっては、HOC を動的に適用する必要があります。これはライフサイクル関数またはコンストラクターで行う必要があります
3. 静的メソッドは手動でコピーする必要があります
の React コンポーネントで静的メソッドを定義すると非常に便利な場合があります。 HOC をコンポーネントに適用すると、元のコンポーネントはコンテナ コンポーネントにラップされますが、返される新しいコンポーネントには元のコンポーネントの静的メソッドが含まれません。
// Define a static method WrappedComponent.staticMethod = function() {/*...*/} // Now apply an HOC const EnhancedComponent = enhance(WrappedComponent); // The enhanced component has no static method typeof EnhancedComponent.staticMethod === 'undefined' // true
返されたコンポーネントが元のコンポーネントの静的メソッドを持つようにするには、元のコンポーネントの静的メソッドを関数内の新しいコンポーネントにコピーする必要があります。
function enhance(WrappedComponent) { class Enhance extends React.Component {/*...*/} // Must know exactly which method(s) to copy :( // 你也能够借助第三方工具 Enhance.staticMethod = WrappedComponent.staticMethod; return Enhance; }
4. コンテナコンポーネントの ref はラップされたコンポーネントに渡されません
コンテナコンポーネントの props はラップされたコンポーネントに簡単に渡せますが、コンテナコンポーネントの ref は渡されませんラップされたコンポーネントに。 HOC を通じて返されるコンポーネントの ref を設定する場合、この ref はラップされたコンポーネントではなく、最も外側のコンテナ コンポーネントを参照します。
関連する推奨事項
とても簡単な例を使ってreact.jsの高次コンポーネントの考え方を理解する
以上がReact の高次コンポーネントの分析例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。