Maison  >  Article  >  interface Web  >  Explorez les meilleures pratiques pour introduire des composants d'ordre supérieur dans React

Explorez les meilleures pratiques pour introduire des composants d'ordre supérieur dans React

WBOY
WBOYoriginal
2023-08-31 23:49:021301parcourir

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

Il s'agit de la troisième partie de la série de composants de haut niveau. Dans ce premier tutoriel, nous partons de zéro. Nous avons appris les bases de la syntaxe ES6, des fonctions d'ordre supérieur et des composants d'ordre supérieur.

Les modèles de composants d'ordre supérieur sont utiles pour créer des composants abstraits : vous pouvez les utiliser pour partager des données (état et comportement) avec des composants existants. Dans la deuxième partie de cette série, je présente un exemple pratique de code utilisant ce modèle. Cela inclut le routage protégé, la création de conteneurs génériques configurables, l'attachement d'indicateurs de chargement aux composants, etc.

Dans ce didacticiel, nous examinerons certaines des meilleures pratiques et considérations à prendre en compte lors de la rédaction de HOC.

Présentation

React avait quelque chose appelé Mixins qui fonctionnait très bien avec les méthodes React.createClass. Les mixins permettent aux développeurs de partager du code entre les composants. Cependant, ils présentaient certains inconvénients et l’idée fut finalement abandonnée. Les mixins n'ont pas été mis à niveau pour prendre en charge les classes ES6, et Dan Abramov a même écrit un article détaillé expliquant pourquoi les mixins sont considérés comme dangereux.

Des composants d'ordre supérieur sont apparus pour remplacer les Mixins et prennent en charge les classes ES6. De plus, HOC ne nécessite aucune action avec l'API React et constitue un modèle général qui fonctionne bien avec React. Cependant, les HOC présentent également des inconvénients. Bien que les inconvénients des composants d'ordre supérieur ne soient pas évidents dans les petits projets, vous pouvez lier plusieurs composants d'ordre supérieur à un seul composant, comme indiqué ci-dessous.

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

Vous ne devriez pas laisser vos liens arriver au point où vous vous posez des questions telles que : « D'où viennent ces accessoires ? » Ce didacticiel aborde certains problèmes courants liés au modèle de composant d'ordre supérieur et propose des solutions pour les résoudre correctement.

Question HOC

Certains problèmes courants liés aux HOC ont moins à voir avec les HOC eux-mêmes qu'avec leur mise en œuvre.

Comme vous le savez, HOC est idéal pour l'abstraction de code et la création de code réutilisable. Cependant, lorsque plusieurs HOC sont empilés, il peut être difficile de déboguer si quelque chose ne semble pas correct ou si certains accessoires n'apparaissent pas, car React DevTools vous donne des indices très limités sur ce qui pourrait ne pas fonctionner.

Problèmes HOC du monde réel

Pour comprendre les inconvénients des HOC, j'ai créé un exemple de démo imbriqué avec certains des HOC que nous avons créés dans le didacticiel précédent. Nous avons quatre fonctions d’ordre supérieur encapsulant un seul composant ContactList. Si le code n'a pas de sens ou si vous n'avez pas suivi mon tutoriel précédent, voici un bref résumé de son fonctionnement.

withRouter est un HOC et fait partie du package React-router. Il vous permet d'accéder aux propriétés de l'objet historique, puis de les transmettre comme accessoires.

withAuth 查找 authentication 属性,如果身份验证为 true,则呈现 WrappedComponent。如果身份验证为 false,则会将 '/login' Pousser vers un objet historique.

withGenericContainer 除了 WrappedComponent 之外还接受一个对象作为输入。 GenericContainer Effectuez un appel API et stockez le résultat dans l'état, puis envoyez les données sous forme d'accessoires au composant encapsulé.

withLoader est un HOC avec un indicateur de chargement supplémentaire. L'indicateur tourne jusqu'à ce que les données acquises atteignent l'état.

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="Explorez les meilleures pratiques pour introduire des composants dordre supérieur dans 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;

Vous pouvez désormais constater par vous-même certains pièges courants des composants d'ordre supérieur. Discutons de certains d’entre eux en détail.

Précautions de base

N'oubliez pas de diffuser les accessoires dans HOC

Supposons que nous ayons un authenticated = { this.state.authenticated } 属性。我们知道这是一个重要的道具,并且应该将其一直延伸到演示组件。然而,想象一下中间 HOC,例如 withGenericContainer au sommet de la hiérarchie de composition et décidons d'ignorer tous ses accessoires.

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

Il s'agit d'une erreur très courante et doit être évitée lors de l'écriture de composants d'ordre supérieur. Les personnes qui ne sont pas familières avec les HOC peuvent avoir du mal à comprendre pourquoi tous les accessoires manquent, car il est difficile d'isoler le problème. Alors, n'oubliez pas de propager les accessoires dans votre HOC.

//The right way

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

Ne faites pas passer des accessoires inexistants au-delà de la portée du HOC

HOC peut introduire de nouvelles propriétés dans WrappedComponent qui peuvent ne pas être d'aucune utilité. Dans ce cas, c'est une bonne pratique de transmettre des accessoires qui ne concernent que le composant composé.

Les composants d'ordre supérieur peuvent accepter des données de deux manières : en tant que paramètres de fonctions ou en tant qu'accessoires de composants. Par exemple, dans authenticated = { this.state.authenticated } 是一个 prop 示例,而在 withGenericContainer(reqAPI)(ContactList), nous transmettons les données en tant que paramètres.

因为 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 决定应该渲染什么。

En d'autres termes, l'état de Mouse 组件接受一个函数作为子属性的值。当 Mouse 渲染时,它返回 Mouse et la fonction render prop peuvent l'utiliser à leur guise.

Ce que j'aime dans ce mode :

  • Du point de vue de la lisibilité, la source des accessoires est plus évidente.
  • Ce mode est dynamique et flexible. HOC est composé en temps statique. Bien que je n'ai jamais trouvé cela comme une limitation, les accessoires de rendu sont combinés dynamiquement et plus flexibles.
  • Composition simplifiée des composants. Vous pouvez dire adieu à l’imbrication de plusieurs HOC.

Conclusion

Les composants d'ordre supérieur sont un modèle qui peut être utilisé pour créer des composants robustes et réutilisables dans React. Si vous envisagez d'utiliser un HOC, vous devez suivre quelques règles de base. Ceci afin que vous ne regrettiez pas votre décision de les utiliser plus tard. J'ai résumé la plupart des meilleures pratiques dans ce tutoriel.

HOC n'est pas le seul modèle populaire de nos jours. À la fin de ce tutoriel, je vous présente un autre modèle appelé render props, qui devient de plus en plus populaire parmi les développeurs React.

Je ne jugerai pas un mode et ne dirai pas que celui-ci est meilleur qu'un autre. À mesure que React évolue et que l’écosystème qui l’entoure mûrit, de plus en plus de modèles émergeront. À mon avis, vous devriez tous les apprendre et vous en tenir à celui qui correspond à votre style et avec lequel vous vous sentez à l'aise.

Cela marque également la fin de la série de didacticiels de haut niveau sur les composants. Nous sommes partis de zéro et maîtrisons une technologie avancée appelée HOC. Si j'ai raté quelque chose ou si vous avez des suggestions/idées, j'aimerais les entendre. Vous pouvez les poster dans les commentaires.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn