Погрузитесь в React Higher Order Components (HOC)

внешний интерфейс React.js Medium Redux

Что такое ХОК?

HOC (полное название Higher-order component) — это продвинутый метод использования React, в основном для облегчения повторного использования компонентов. HOC — это метод, который принимает компонент и возвращает компонент более высокого уровня.

Когда использовать ХОК?

В процессе разработки React обнаруживается, что существует множество ситуаций, в которых компоненты необходимо «улучшить», например, добавить или изменить некоторые конкретные свойства компонента, некоторое управление разрешениями или некоторые другие оптимизации. И если эта функция для нескольких компонентов, и каждый компонент пишет один и тот же набор кода одновременно, это явно не очень разумно, поэтому вы можете рассмотреть возможность использования HOC.

Chestnut: метод соединения react-redux — это HOC, он получает компонент wrapped и добавляет необходимые реквизиты в файл wrapComponent в соединении.

Простая реализация HOC

HOC — это не просто метод, это должна быть фабрика компонентов для получения компонентов низкого уровня и создания компонентов высокого уровня.

Простейшая реализация HOC выглядит так:

function HOCFactory(WrappedComponent) {
  return class HOC extends React.Component {
    render(){
      return <WrappedComponent {...this.props} />
    }
  }
}

Что может ХОК?

  • Повторное использование кода, модульность кода
  • Добавить, удалить или изменить реквизит
  • рендеринг угона

На самом деле, в дополнение к повторному использованию кода и модуляризации, то, что делает HOC, на самом деле является захватом.Поскольку входящий wrapComponent визуализируется как дочерний, реквизиты, переданные вышестоящим, напрямую передаются в HOC, поэтому компонент HOC имеет большое разрешение. для изменения реквизита и управления рендерингом.

Добавить, удалить или изменить реквизит

Эффект добавления, удаления или изменения реквизита может быть достигнут путем изменения входящих реквизитов или добавления новых реквизитов.

Например, если вы хотите добавить свойства в wrapComponent, вы можете сделать это следующим образом:

function control(wrappedComponent) {
  return class Control extends React.Component {
    render(){
      let props = {
        ...this.props,
        message: "You are under control"
      };
      return <wrappedComponent {...props} />
    }
  }
}

Таким образом, вы можете использовать реквизиты сообщений в своих компонентах:

class MyComponent extends React.Component {
  render(){
    return <div>{this.props.message}</div>
  }
}

export default control(MyComponent);

рендеринг угона

Перехват рендеринга здесь не в том, что вы можете контролировать детали его рендеринга, а в том, чтобы контролировать, нужно ли рендерить. Поскольку детали контролируются методом рендеринга внутри компонента, вы не можете управлять деталями рендеринга.

Например, если компонент хочет загрузить... когда данные не загружены, это можно написать так:

function loading(wrappedComponent) {
  return class Loading extends React.Component {
    render(){
      if(!this.props.data) {
        return <div>loading...</div>
      }
      return <wrappedComponent {...props} />
    }
  }
}

Таким образом, когда родитель не передает данные, в этом разделе будет отображаться только загрузка..., а конкретное содержимое компонента отображаться не будет.

class MyComponent extends React.Component {
  render(){
    return <div>{this.props.data}</div>
  }
}

export default control(MyComponent);

Каковы варианты использования HOC?

React Redux

Самым классическим является метод подключения React Redux (особенно вconnectAdvancedреализовано в).

С помощью этого метода HOC прослушайте хранилище избыточности, а затем привяжите состояние (полученное с помощью mapStateToProps) и создателя действия (полученное с помощью mapDispatchToProps), требуемое подчиненным компонентом, к реквизитам упакованного компонента.

регистратор и отладчик

Это тот, что на официальном сайтеПример, который можно использовать для отслеживания изменений реквизитов, переданных родительским компонентом:

function logProps(WrappedComponent) {
  return class extends React.Component {
    componentWillReceiveProps(nextProps) {
      console.log(`WrappedComponent: ${WrappedComponent.displayName}, Current props: `, this.props);
      console.log(`WrappedComponent: ${WrappedComponent.displayName}, Next props: `, nextProps);
    }
    render() {
      // Wraps the input component in a container, without mutating it. Good!
      return <WrappedComponent {...this.props} />;
    }
  }
}

Управление разрешениями страницы

Компонент может быть обернут HOC, при переходе на текущую страницу проверьте, есть ли у пользователя соответствующее разрешение. Отобразите страницу, если она есть. Если нет, перейдите на другую страницу (например, страницу без разрешений или целевую страницу).

Также можно предоставить API разрешений для текущего компонента, а логическое определение разрешений также можно выполнить внутри страницы.

На что следует обратить внимание при использовании HOC?

Старайтесь не изменять произвольно реквизиты, требуемые подчиненными компонентами. Причина этого в том, что существует определенный риск при изменении реквизитов, переданных от родителя к подчиненному, что может привести к ошибкам в подчиненных компонентах. Например, если реквизиты имени изначально требовались, но были удалены в HOC, подчиненные компоненты могут не отображаться нормально или даже будет сообщено об ошибке.

Реф не может получить реф, которого вы хотите

Ранее вы использовали в родительском компоненте<component ref="component"/>, вы можете напрямую пройтиthis.refs.componentчтобы получить. Но поскольку компонент здесь инкапсулирован HOC, он уже является компонентом HOC, поэтому вы не можете получить тот, который хотите.ref(wrappedComponent的ref).

Чтобы решить эту проблему, есть два пути:

a)Как и метод подключения React Redux, добавьте параметр внутри, напримерwithRef, при установленном флажке в компоненте добавить реф на подчиненный компонент и получить его через метод getWrappedInstance.

Каштан:

function HOCFactory(wrappedComponent) {
  return class HOC extends React.Component {
    getWrappedInstance = ()=>{
      if(this.props.widthRef) {
        return this.wrappedInstance;
      }
    }

    setWrappedInstance = (ref)=>{
      this.wrappedInstance = ref;
    }

    render(){
      let props = {
        ...this.props
      };

      if(this.props.withRef) {
        props.ref = this.setWrappedInstance;
      }

      return <wrappedComponent {...props} />
    }
  }
}

export default HOCFactory(MyComponent);

Таким образом, вы можете получить значение ref MyComponent, подобное этому, в родительском компоненте.

class ParentCompoent extends React.Component {
  doSomethingWithMyComponent(){
    let instance = this.refs.child.getWrappedInstance();
    // ....
  }

  render(){
    return <MyComponent ref="child" withRef />
  }
}

b)Есть еще один способ, упомянутый на официальном сайте: Родитель получает ссылку, передавая метод, см. каштан:

Сначала посмотрите на родительский компонент:

class ParentCompoent extends React.Component {
  getInstance = (ref)=>{
    this.wrappedInstance = ref;
  }

  render(){
    return <MyComponent getInstance={this.getInstance} />
  }
}

В HOC просто передайте метод getInstance как метод ref.

function HOCFactory(wrappedComponent) {
  return class HOC extends React.Component {
    render(){
      let props = {
        ...this.props
      };

      if(typeof this.props.getInstance === "function") {
        props.ref = this.props.getInstance;
      }

      return <wrappedComponent {...props} />
    }
  }
}

export default HOCFactory(MyComponent);

Статический метод, связанный с компонентом, будет потерян.

Например, вы изначально привязали некоторые статические методы к компоненту.MyComponent.staticMethod = o=>o. Однако из-за пакета HOC родительский компонент больше не является исходным компонентом, поэтому, конечно, нельзя получить метод staticMethod.

Пример с официального сайта:

// 定义一个static方法
WrappedComponent.staticMethod = function() {/*...*/}
// 利用HOC包裹
const EnhancedComponent = enhance(WrappedComponent);

// 返回的方法无法获取到staticMethod
typeof EnhancedComponent.staticMethod === 'undefined' // true

Вот обходной путь, компонент hoist-non-react-statics, который автоматически привязывает все нереакт-методы, привязанные к объекту, к новому объекту:

import hoistNonReactStatic from 'hoist-non-react-statics';
function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  hoistNonReactStatic(Enhance, WrappedComponent);
  return Enhance;
}

заключительные замечания

Модель HOC полезна, когда вам нужно делать плагины React.

Я надеюсь, что эта статья поможет вам получить общее представление о HOC и вдохновить его.

Кроме того, этоСтатьи на средеЭто даст вам больше вдохновения.В этой статье то, о чем я говорю здесь, разделено на Props Proxy HOC, и есть еще один HOC Inheritance Inversion, который настоятельно рекомендуется взглянуть.