Heim  >  Artikel  >  Web-Frontend  >  Entdecken Sie Best Practices für die Einführung von Komponenten höherer Ordnung in React

Entdecken Sie Best Practices für die Einführung von Komponenten höherer Ordnung in React

WBOY
WBOYOriginal
2023-08-31 23:49:021302Durchsuche

探索在 React 中引入高阶组件的最佳实践

Dies ist der dritte Teil der High-Level-Komponentenserie. In diesem ersten Tutorial beginnen wir bei Null. Wir haben die Grundlagen der ES6-Syntax, Funktionen höherer Ordnung und Komponenten höherer Ordnung erlernt.

Komponentenmuster höherer Ordnung sind nützlich zum Erstellen abstrakter Komponenten – Sie können sie verwenden, um Daten (Zustand und Verhalten) mit vorhandenen Komponenten zu teilen. Im zweiten Teil dieser Serie zeige ich anhand dieses Musters ein praktisches Codebeispiel. Dazu gehören geschütztes Routing, die Erstellung konfigurierbarer generischer Container, das Anbringen von Ladeindikatoren an Komponenten und mehr.

In diesem Tutorial werfen wir einen Blick auf einige der Best Practices und Überlegungen, die Sie beim Schreiben von HOCs berücksichtigen sollten.

Einführung

React hatte früher etwas namens Mixins, das mit React.createClass Methoden wirklich gut funktionierte. Mixins ermöglichen Entwicklern die gemeinsame Nutzung von Code zwischen Komponenten. Sie hatten jedoch einige Nachteile und die Idee wurde schließlich aufgegeben. Mixins wurden nicht aktualisiert, um ES6-Klassen zu unterstützen, und Dan Abramov hat sogar einen ausführlichen Artikel geschrieben, in dem er erklärt, warum Mixins als schädlich gelten.

Komponenten höherer Ordnung entstanden als Ersatz für Mixins und unterstützen ES6-Klassen. Darüber hinaus erfordert HOC keine Arbeit mit der React-API und ist ein allgemeines Muster, das gut mit React funktioniert. Allerdings haben HOCs auch Nachteile. Obwohl die Nachteile von Komponenten höherer Ordnung in kleineren Projekten möglicherweise nicht offensichtlich sind, können Sie mehrere Komponenten höherer Ordnung zu einer einzigen Komponente verknüpfen, wie unten gezeigt.

const SomeNewComponent = 
        withRouter(RequireAuth(LoaderDemo(GenericContainer(CustomForm(Form)))))

Sie sollten Ihre Links nicht so weit bringen, dass Sie sich Fragen stellen wie: „Woher kommen diese Requisiten?“ Dieses Tutorial behandelt einige häufige Probleme mit dem Muster „Higher Order Component“ und Lösungen für deren korrekte Lösung.

HOC-Frage

Einige häufige Probleme im Zusammenhang mit HOCs haben weniger mit den HOCs selbst als vielmehr mit ihrer Umsetzung zu tun.

Wie Sie wissen, eignet sich HOC hervorragend zur Codeabstraktion und zum Erstellen von wiederverwendbarem Code. Wenn Sie jedoch mehrere HOCs gestapelt haben, kann das Debuggen mühsam sein, wenn etwas nicht richtig aussieht oder bestimmte Requisiten nicht angezeigt werden, da React DevTools Ihnen nur sehr begrenzte Hinweise darauf gibt, was möglicherweise schief läuft.

Reale HOC-Probleme

Um die Nachteile von HOCs zu verstehen, habe ich eine Beispieldemo erstellt, die mit einigen der HOCs verschachtelt ist, die wir im vorherigen Tutorial erstellt haben. Wir haben vier Funktionen höherer Ordnung, die eine einzelne ContactList-Komponente umschließen. Wenn der Code keinen Sinn ergibt oder Sie mein vorheriges Tutorial nicht befolgt haben, finden Sie hier eine kurze Zusammenfassung seiner Funktionsweise.

withRouter ist ein HOC und Teil des React-Router-Pakets. Es ermöglicht Ihnen, auf die Eigenschaften des Verlaufsobjekts zuzugreifen und diese dann als Requisiten zu übergeben.

withAuth 查找 authentication 属性,如果身份验证为 true,则呈现 WrappedComponent。如果身份验证为 false,则会将 '/login' Auf historisches Objekt schieben.

withGenericContainer 除了 WrappedComponent 之外还接受一个对象作为输入。 GenericContainer Führen Sie einen API-Aufruf durch, speichern Sie das Ergebnis im Status und senden Sie die Daten dann als Requisiten an die verpackte Komponente.

withLoader ist ein HOC mit zusätzlicher Ladeanzeige. Der Indikator dreht sich, bis die erfassten Daten den Status erreichen.

BestPracticeDemo.jsx

class BestPracticesDemo extends Component {

    render() {

		return(
            <div className="contactApp">
    			<ExtendedContactList authenticated = {true} {...this.props} contacts ="this" />
    	    </div>
     	)
	}
}

const ContactList = ({contacts}) => {
	
	return(
		<div>
			<ul>
      {contacts.map(
        (contact) => <li key={contact.email}>
         
          <img src={contact.photo}    style="max-width:90%" height="100px"  alt="Entdecken Sie Best Practices für die Einführung von Komponenten höherer Ordnung in React" />
          <div className="contactData">
          <h4>{contact.name}</h4>
           <small>{contact.email}</small>  <br/><small> {contact.phone}</small>
          </div>
         
        </li>
      )}
    </ul>
		</div>
		)
}

const reqAPI = {reqUrl: 'https://demo1443058.mockable.io/users/', 
                reqMethod:'GET', resName:'contacts'}	

const ExtendedContactList = withRouter(
                                withAuth(
                                    withGenericContainer(reqAPI)(
                                        withLoader('contacts')
                                            (ContactList))));

export default BestPracticesDemo;

Jetzt können Sie sich selbst ein Bild von einigen häufigen Fallstricken von Komponenten höherer Ordnung machen. Lassen Sie uns einige davon im Detail besprechen.

Grundlegende Vorsichtsmaßnahmen

Vergessen Sie nicht, die Requisiten im HOC zu verteilen

Angenommen, wir haben ein authenticated = { this.state.authenticated } 属性。我们知道这是一个重要的道具,并且应该将其一直延伸到演示组件。然而,想象一下中间 HOC,例如 withGenericContainer an der Spitze der Kompositionshierarchie und beschließen, alle seine Requisiten zu ignorieren.

//render method of withGenericContainer
render() {
	return(
		<WrappedComponent />
    )
}

Dies ist ein sehr häufiger Fehler und sollte beim Schreiben von Komponenten höherer Ordnung vermieden werden. Für Personen, die mit HOCs nicht vertraut sind, kann es schwierig sein herauszufinden, warum alle Requisiten fehlen, da es schwierig ist, das Problem einzugrenzen. Denken Sie also immer daran, Requisiten in Ihrem HOC zu verbreiten.

//The right way

render() {
	return(
		<WrappedComponent {...this.props} {...this.state} />)
}

Geben Sie keine nicht vorhandenen Requisiten über den Geltungsbereich des HOC hinaus

HOC führt möglicherweise neue Eigenschaften zu WrappedComponent ein, die möglicherweise keinen Nutzen haben. In diesem Fall empfiehlt es sich, Requisiten zu übergeben, die nur für die zusammengesetzte Komponente relevant sind.

Komponenten höherer Ordnung können Daten auf zwei Arten akzeptieren: als Parameter von Funktionen oder als Requisiten von Komponenten. In authenticated = { this.state.authenticated } 是一个 prop 示例,而在 withGenericContainer(reqAPI)(ContactList) übergeben wir beispielsweise Daten als Parameter.

因为 withGenericContainer 是一个函数,所以您可以根据需要传入任意数量的参数。在上面的示例中,配置对象用于指定组件的数据依赖性。然而,增强组件和包装组件之间的契约是严格通过 props 进行的。

因此,我建议通过函数参数填充静态时间数据依赖项,并将动态数据作为 props 传递。经过身份验证的道具是动态的,因为用户可以通过身份验证,也可以不通过身份验证,具体取决于他们是否登录,但我们可以确定 reqAPI 对象的内容不会动态更改。

不要在渲染方法中使用 HOC

这是一个您应该不惜一切代价避免的示例。

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 所做的更改将被覆盖。为了避免这种情况,您应该坚持组合组件而不是改变它们。

命名空间通用 Propnames

当您有多个堆叠时,命名空间道具名称的重要性是显而易见的。组件可能会将 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;

withMousewithCat 都在尝试推送自己的 name 版本。如果EnhancedComponent也必须共享一些同名的props怎么办?

<EnhancedComponent name="This is important" />

这不会给最终开发人员带来混乱和误导吗? React Devtools 不会报告任何名称冲突,您必须查看 HOC 实现细节才能了解出了什么问题。

这可以通过提供 HOC 属性名称的范围作为约定来解决。因此,您将拥有 withCat_namewithMouse_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,并且 NameComponentWrappedComponent,则 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 决定应该渲染什么。

Mit anderen Worten, der Zustand von Mouse 组件接受一个函数作为子属性的值。当 Mouse 渲染时,它返回 Mouse und die Render-Prop-Funktion können ihn nach Belieben verwenden.

Was mir an diesem Modus gefällt:

  • Aus Sicht der Lesbarkeit ist die Quelle der Requisiten offensichtlicher.
  • Dieser Modus ist dynamisch und flexibel. HOC wird in statischer Zeit komponiert. Obwohl ich das nie als Einschränkung empfunden habe, werden Render-Requisiten dynamisch kombiniert und sind flexibler.
  • Vereinfachte Komponentenzusammensetzung. Sie können sich von der Verschachtelung mehrerer HOCs verabschieden.

Fazit

Komponenten höherer Ordnung sind ein Muster, mit dem robuste, wiederverwendbare Komponenten in React erstellt werden können. Wenn Sie ein HOC verwenden möchten, sollten Sie einige Grundregeln befolgen. Damit Sie Ihre Entscheidung, sie später zu verwenden, nicht bereuen. Die meisten Best Practices habe ich in diesem Tutorial zusammengefasst.

HOC ist heutzutage nicht das einzige beliebte Modell. Am Ende dieses Tutorials stelle ich Ihnen ein weiteres Muster namens Render Props vor, das bei React-Entwicklern immer beliebter wird.

Ich werde nicht einen Modus beurteilen und sagen, dieser ist besser als ein anderer. Während sich React weiterentwickelt und das Ökosystem um es herum reift, werden immer mehr Muster entstehen. Meiner Meinung nach sollten Sie sie alle lernen und sich an diejenige halten, die zu Ihrem Stil passt und mit der Sie sich wohl fühlen.

Dies markiert auch das Ende der Tutorialreihe zu Komponenten auf hohem Niveau. Wir haben bei Null angefangen und beherrschen eine fortschrittliche Technologie namens HOC. Wenn ich etwas verpasst habe oder Sie Vorschläge/Ideen haben, würde ich mich freuen, diese zu hören. Sie können sie in den Kommentaren posten.

Das obige ist der detaillierte Inhalt vonEntdecken Sie Best Practices für die Einführung von Komponenten höherer Ordnung in React. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn