これは、高レベル コンポーネント シリーズの 3 番目のパートです。この最初のチュートリアルでは、最初から始めます。 ES6 の構文、高階関数、高階コンポーネントの基本を学びました。
高次コンポーネント パターンは、抽象コンポーネントの作成に役立ちます。これらを使用して、既存のコンポーネントとデータ (状態と動作) を共有できます。このシリーズの第 2 部では、このパターンを使用したコードの実際の例を示します。これには、保護されたルーティング、構成可能な汎用コンテナーの作成、コンポーネントへの読み込みインジケーターの添付などが含まれます。
このチュートリアルでは、HOC を作成する際に考慮すべきいくつかのベスト プラクティスと考慮事項について説明します。
###導入### メソッドとうまく連携する Mixins と呼ばれるものがありました。ミックスインを使用すると、開発者はコンポーネント間でコードを共有できます。しかし、それらにはいくつかの欠点があり、このアイデアは最終的に放棄されました。ミックスインは ES6 クラスをサポートするようにアップグレードされておらず、ダン・アブラモフはミックスインが有害であると考えられる理由を説明する詳細な記事さえ書きました。
Mixins の代わりに高次コンポーネントが登場し、ES6 クラスをサポートします。さらに、HOC は React API を使用する必要がなく、React で適切に動作する一般的なパターンです。ただし、HOC には欠点もあります。高次コンポーネントの欠点は小規模なプロジェクトでは明らかではないかもしれませんが、以下に示すように、複数の高次コンポーネントを 1 つのコンポーネントにリンクできます。
「これらのプロパティはどこから来たのか?」という質問を自問するような状態にリンクを誘導しないでください。このチュートリアルでは、高次コンポーネント パターンに関するいくつかの一般的な問題とその解決策について説明します。それらを正しく。
HOCの質問
ご存知のとおり、HOC はコードの抽象化と再利用可能なコードの作成に最適です。ただし、複数の HOC がスタックされている場合、何かが正しく見えない場合や、特定のプロパティが表示されない場合、デバッグが面倒になることがあります。これは、React DevTools が、何が問題になっているのかについて非常に限られた手がかりしか提供しないためです。
現実世界の HOC 問題
は HOC であり、React-router パッケージの一部です。これにより、履歴オブジェクトのプロパティにアクセスし、それらを props として渡すことができます。
authentication
プロパティを検索し、認証が true の場合は WrappedComponent
をレンダリングします。認証が false の場合、「/login
」が履歴オブジェクトにプッシュされます。
WrappedComponent
に加えてオブジェクトを入力として受け入れます。 GenericContainer
API 呼び出しを実行し、結果を状態に保存し、データをプロップとしてラップされたコンポーネントに送信します。
は、追加の読み込みインジケーターを備えた HOC です。取得したデータがステータスに達するまでインジケーターが回転します。
BestPracticeDemo.jsx
基本的な注意事項
プロパティがあるとします。これが重要な小道具であることはわかっており、プレゼンテーション コンポーネントまで拡張する必要があります。ただし、withGenericContainer
などの中間 HOC がそのプロパティをすべて無視することを決定したと想像してください。
リーリー
これは非常によくある間違いであり、高次のコンポーネントを作成する場合には避けるべきです。 HOC に詳しくない人は、問題の切り分けが難しいため、すべてのプロパティが欠落している理由を理解するのが難しいかもしれません。したがって、HOC 内でプロップを伝播することを常に忘れないでください。
HOC の範囲を超えて存在しない props を渡さないでください
高階コンポーネントは、関数のパラメータとして、またはコンポーネントのプロパティとしてという 2 つの方法でデータを受け入れることができます。たとえば、
authenticated = { this.state.authenticated } は prop の例ですが、withGenericContainer(reqAPI)(ContactList)
ではデータをパラメーターとして渡します。
<p>因为 withGenericContainer 是一个函数,所以您可以根据需要传入任意数量的参数。在上面的示例中,配置对象用于指定组件的数据依赖性。然而,增强组件和包装组件之间的契约是严格通过 props 进行的。 </p>
<p>因此,我建议通过函数参数填充静态时间数据依赖项,并将动态数据作为 props 传递。经过身份验证的道具是动态的,因为用户可以通过身份验证,也可以不通过身份验证,具体取决于他们是否登录,但我们可以确定 <code class="inline">reqAPI
对象的内容不会动态更改。
这是一个您应该不惜一切代价避免的示例。
var OriginalComponent = () => <p>Hello world.</p>; class App extends React.Component { render() { return React.createElement(enhanceComponent(OriginalComponent)); } };
除了性能问题之外,您还将在每次渲染时丢失 OriginalComponent
及其所有子组件的状态。要解决这个问题,请将 HOC 声明移到 render 方法之外,使其仅创建一次,以便渲染始终返回相同的EnhancedComponent。
var OriginalComponent = () => <p>Hello world.</p>; var EnhancedComponent = enhanceComponent(OriginalComponent); class App extends React.Component { render() { return React.createElement(EnhancedComponent); } };
改变 HOC 内的包装组件将导致无法在 HOC 外部使用包装组件。如果您的 HOC 返回 WrappedComponent,您几乎总是可以确定自己做错了。下面的例子演示了突变和组合之间的区别。
function logger(WrappedComponent) { WrappedComponent.prototype.componentWillReceiveProps = function(nextProps) { console.log('Current props: ', this.props); console.log('Next props: ', nextProps); }; // We're returning the WrappedComponent rather than composing //it return WrappedComponent; }
组合是 React 的基本特征之一。您可以在其渲染函数中将一个组件包装在另一个组件内,这就是所谓的组合。
function logger(WrappedComponent) { return class extends 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} />; } } }
此外,如果您改变 HOC 内的 WrappedComponent,然后使用另一个 HOC 包装增强组件,则第一个 HOC 所做的更改将被覆盖。为了避免这种情况,您应该坚持组合组件而不是改变它们。
当您有多个堆叠时,命名空间道具名称的重要性是显而易见的。组件可能会将 prop 名称推送到已被另一个高阶组件使用的 WrappedComponent 中。
import React, { Component } from 'react'; const withMouse = (WrappedComponent) => { return class withMouse extends Component { constructor(props) { super(props); this.state = { name: 'Mouse' } } render() { return( <WrappedComponent {...this.props} name={this.state.name} /> ); } } } const withCat = (WrappedComponent) => { return class withCat extends Component { render() { return( <WrappedComponent {...this.props} name= "Cat" /> ) } } } const NameComponent = ({name}) => { return( <div> {name} </div>) } const App =() => { const EnhancedComponent = withMouse(withCat(NameComponent)); return( <div> <EnhancedComponent /> </div>) } export default App;
withMouse
和 withCat
都在尝试推送自己的 name 版本。如果EnhancedComponent也必须共享一些同名的props怎么办?
<EnhancedComponent name="This is important" />
这不会给最终开发人员带来混乱和误导吗? React Devtools 不会报告任何名称冲突,您必须查看 HOC 实现细节才能了解出了什么问题。
这可以通过提供 HOC 属性名称的范围作为约定来解决。因此,您将拥有 withCat_name
和 withMouse_name
而不是通用的 prop 名称。
这里需要注意的另一件有趣的事情是,对属性进行排序在 React 中非常重要。当您多次拥有相同的属性并导致名称冲突时,最后一个声明将始终保留。在上面的例子中,Cat 获胜,因为它被放置在 { ...this.props }
之后。
如果您希望通过其他方式解决名称冲突,您可以重新排序属性并在最后传播 this.props
。这样,您就可以设置适合您的项目的合理默认值。
由 HOC 创建的组件在 React Devtools 中显示为普通组件。很难区分两者。您可以通过为高阶组件提供有意义的 displayName
来简化调试。在 React Devtools 上拥有这样的东西不是明智的吗?
<withMouse(withCat(NameComponent)) > ... </withMouse(withCat(NameComponent))>
那么 displayName
是什么?每个组件都有一个 displayName
属性,可用于调试目的。最流行的技术是包装 WrappedComponent
的显示名称。如果 withCat
是 HOC,并且 NameComponent
是 WrappedComponent
,则 displayName
将是 withCat(NameComponent)
.
const withMouse = (WrappedComponent) => { class withMouse extends Component { /* */ } withMouse.displayName = `withMouse(${getDisplayName(WrappedComponent)})`; return withMouse; } const withCat = (WrappedComponent) => { class withCat extends Component { /* */ } withCat.displayName = `withCat(${getDisplayName(WrappedComponent)})`; return withCat; } function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component'; }
尽管 Mixins 已经消失,但说高阶组件是唯一允许代码共享和抽象的模式是有误导性的。另一种替代模式已经出现,我听说有人说它比 HOC 更好。深入探讨这个概念超出了本教程的范围,但我将向您介绍渲染道具和一些基本示例,以演示它们为何有用。
渲染道具有许多不同的名称:
这是一个简单的示例,应该解释渲染道具的工作原理。
class Mouse extends Component { constructor() { super(); this.state = { name: "Nibbles" } } render() { return( <div> {this.props.children(this.state)} </div> ) } } class App extends Component { render() { return( <Mouse> {(mouse) => <div> The name of the mouse is {mouse.name} </div> } </Mouse> ) } }
如您所见,我们已经摆脱了高阶函数。我们有一个名为 Mouse
的常规组件。我们将渲染 this.props.children()
并将状态作为参数传递,而不是在其 render 方法中渲染包装的组件。所以我们给 Mouse
一个 render prop,而 render prop 决定应该渲染什么。
つまり、Mouse
コンポーネントは、子プロパティの値として関数を受け入れます。 Mouse
がレンダリングされると、Mouse
の状態が返され、render prop 関数はそれを自由に使用できます。
このモデルの好きなところ:
現在人気のモデルはHOCだけではありません。このチュートリアルの最後では、Render props と呼ばれる別のパターンを紹介します。これは、React 開発者の間でますます人気が高まっています。
私は、あるモードを判断して、このモードが他のモードよりも優れているとは言いません。 React が進化し、それを取り巻くエコシステムが成熟するにつれて、より多くのパターンが出現するでしょう。私の意見では、それらをすべて学び、自分のスタイルに合った、快適に感じるものを使用する必要があります。
これで、高レベルのコンポーネントのチュートリアル シリーズも終了となります。私たちはゼロからスタートし、HOCと呼ばれる高度なテクノロジーを習得しました。何か見逃していたり、提案やアイデアがある場合は、ぜひお聞きしたいと思います。コメントに投稿できます。
以上がReact に高次コンポーネントを導入するためのベスト プラクティスを探るの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。