Рубрики
Без рубрики

Реагистрация – составляющая компоненты более высокого порядка (HOCS)

Чтобы просто установить его, компонент более высокого порядка является функцией, которая принимает компонент и возвращает новый компонент. Мне нравится думать о них как о параметризованных компонентах. Много раз я оказываюсь, что создавая несколько компонентов с очень похожей на логику, причем только 1 или 2 изменения. Как только я нахожу этот корпус, как это, очень просто аннотация общая логика, и поместите логику, которая меняется в параметры.

Автор оригинала: Casey Morris.

вступление

Чтобы просто установить его, компонент более высокого порядка является функцией, которая принимает компонент и возвращает новый компонент. Мне нравится думать о них как о параметризованных компонентах. Много раз я оказываюсь, что создавая несколько компонентов с очень похожей на логику, причем только 1 или 2 изменения. Как только я нахожу этот корпус, как это, очень просто аннотация общая логика, и поместите логику, которая меняется в параметры.

Вы можете узнать больше о HOCS здесь , в официальных реагированных документах. Поскольку компоненты являются просто функциями, а HOCS – это просто функции, которые возвращают другие функции, мы можем использовать функциональные концепции для цепи их с использованием методов утилит, таких как составить , который предоставляется многими библиотеками ( Он включен в redux! ).

Я собираюсь поговорить о нескольких общих случаях использования, а затем пройти их внедрение, и несколько способов их можно сочинить вместе, чтобы сделать еще более мощные HOC!

Следуйте вместе (пример приложения)

Вы можете следить с помощью простого приложения RACT IRACT, который я создал, чтобы продемонстрировать следующие концепции и использовать случаи использования. Его можно использовать в браузере или клонированном из репозитория.

Живая песочница: CodeSandox.io/s/github/seysymorrisus/composing-hocs GitHub Repo: github.com/Ssyymorrisus/composing-hocs.

Сценарии использования

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

Погрузчик

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

Ошибка

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

По умолчанию

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

Данные

Компоненты контейнера часто получают данные и передают эти данные как опоры для дочернего компонента. Как правило, единственное, что изменяется между этими компонентами контейнера, является конечной точкой API. Мы также можем использовать HOCS, чтобы легко пройти в Mock Data для целей разработки.

Mockdata

Используется для целей разработки для быстрого прототипа компонентов до того, как конечная точка API была создана в вашем реагированном проекте. Данные и задержка (для MOCK ASYNC Data Futching) поставляются в HOC. Данные передаются на обернутую компонент.

Регистратор

Легко регистрируйте все изменения в процессе (о рендере) для данного компонента, полезной для быстрой отладки.

Реквизит

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

Тайм-ауты

Добавление тайм-аута, которое контролирует состояние в реакции, будет бросать ошибку, если компонент размонтирует, прежде чем функция, прилагаемая к тайм-ауту. Мы можем создать HOC, который обрабатывает и делится функциональностью, чтобы легко добавить и очистить тайм-ауты.

Контейнер

Довольно распространено, чтобы иметь контейнерную компонент, который выбирает данные и оказывает список компонентов, использующих эти данные. Мы можем объединить это с другими HOCS, такими как: asloader, haseRor, andhasdefault для дальнейшего расширения функциональности.

Список

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

HOCS.

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

HASPROPS.

Принимает один параметр, впрыскиваемыеProops и возвращает обернутую компонент с прилагаемыми инъекционными настройками. Полезно, когда вам необходимо вводить реквизиты одному компоненту в филиале, поскольку прилагаемые опоры вводятся как в проходящие, так и неспособности.

const hasProps = injectedProps => WrappedComponent => {
  const HasProps = props => 
  
  return HasProps
}

Использовать:

branch(
  // ...
  hasProps({sample: 'Sample Prop'})(Component)
  // ...
)

Haslogger Принимает один параметр, префикс, который префикрует зарегистрированное сообщение, по умолчанию для пустой строки. Журналы реквизиты к консоли на каждом визуализации Зарченокомпонент Отказ

const hasLogger = (prefix = '') => WrappedComponent => {
  const HasLogger = props => {
    console.log(`${prefix}[Props]:`, props)
    return 
  }
  
  return HasLogger
}

Использовать:

hasLogger(Component)

ветка

Занимает 3 параметра: Тест , ComponentOnpass и ComponentOnfail и возвращает любой из прилагаемых компонентов в зависимости от результата функции тестирования. Если Тест Функция возвращает правда , ComponentOnpass будет возвращен, если ложь , ComponentOnfail будет возвращено. Немедленно возвращает новый компонент в отличие от других HOCS в этом посте.

const branch = (test, ComponentOnPass, ComponentOnFail) => props => test
  ? 
  : ComponentOnFail
    ? 
    : null

Использовать:

branch(testFunction, Component1, Component2)

Hasmockdata.

Занимает 2 параметра: Mockdata и задержка и возвращает обернутый компонент с новым данные пропры Mockdata вводится в данные опора после задержка прошел. Можно установить задержка к 0 Или оставьте пустым, чтобы не иметь задержки. Использует Hastimeouts HOC расширить функциональность для включения addimeout и Clearimeout реквизит.

const hasMockData = (mockData, delay) => WrappedComponent => {
  class HasMockData extends React.Component {
    state = {
      data: [],
      useDefault: true
    }

    componentDidMount() {
      this.props.addTimeout(() => this.setState({data: mockData}), delay)
    }

    componentWillUnmount() {
      this.props.clearTimeouts()
    }

    render() {
      return 
    }
  }

  return hasTimeouts(HasMockData)
}

Использовать:

hasMockData({data: 'This is mock data'}, 1000)(Component)

asloader.

Этот компонент более высокого порядка не имеет параметров. Возвращает обернутую компонент с новой нагрузкой и ожидаемым реквизитом погрузки. Это условно оказывает прилагаемую компонент, если нагрузка ложная. В противном случае он отображает компонент загрузки с поставляемым погрузочным погрузкой.

const hasLoader = WrappedComponent => {
  const HasLoader = props => branch(
    props.loading,
    hasProps({message: props.loadingMessage})(Loading),
    WrappedComponent
  )(props)

  return HasLoader
}

Использовать:

hasLoader(Component)

haserror.

Занимает 1 параметр: Errorcomponent который имеет значение по умолчанию компонента ошибок. Может поставить пользовательский Errorcomponent При желании, а не использовать значение по умолчанию. Возвращает завернутый компонент с новым ожидаемым опоры: Haserror Отказ Это условно делает прилагаемый компонент, если Haserror неверно В противном случае он делает Errorcomponent Отказ

const hasError = (ErrorComponent = Error) => WrappedComponent => {
  const HasError = props =>
    branch(props.hasError, ErrorComponent, WrappedComponent)(props)

  return HasError
}

Использовать:

hasError(CustomErrorComponent)(Component)

Использует по умолчанию Ошибка . Компонент, если ни один не поставлен:

hasError()(Component)

Hasdefault.

Занимает 1 параметр: По умолчанию который ожидает быть реагированным компонентом. Возвращает завернутый компонент с новым ожидаемым опоры: Useefault Отказ Это условно делает прилагаемый компонент, если Useefault это ложь Отказ В противном случае он делает По умолчанию составная часть.

const hasDefault = Default => WrappedComponent => {
  const HasDefault = props =>
    branch(props.useDefault, Default, WrappedComponent)(props)

  return HasDefault
}

Использовать:

hasDefault(DefaultComponent)(Component)

Hasdata

Ожидает объекта одного параметра, который ожидает свойств URL , Пармы и LoadeMessage Отказ URL диктует, какую конечную точку ударил, Пармы вводит параметры URL для запроса и LoadeMessage Позволяет настроить загрузку в рамках Погрузчик составная часть. Использует Axios Получить данные с конечной точки API. Axios может быть легко заменен вашим вашим внедрением выбора. Впрыскивает данные , Haserror , Ошибка . , Useefault , Загрузка и LoadeMessage как реквизиты будут использоваться в обернутом компонентах.

const hasData = ({url, params, loadingMessage}) => WrappedComponent => {
  class HasData extends React.Component {
    state = {
      data: [],
      hasError: false,
      error: {
        title: 'Cannot retrieve Real Posts',
        message: 'Could not retrieve Real Posts from supplied API.'
      },
      useDefault: false,
      loading: false,
      loadingMessage
    }

    componentDidMount() {
      this.setState({loading: true})

      axios.get(url, { params })
      .then(({data}) => {
        this.setState({
          data,
          loading: false,
          hasError: false,
          useDefault: data.length === 0
        })
      })
      .catch(error => {
        console.log(error)
        this.setState({
          hasError: true,
          loading: false
        })
      })
    }

    render() {
      return (
        
      )
    }
  }

  return HasData
}

Использовать:

hasData({
  url: 'https://jsonplaceholder.typicode.com/posts',
  params: {
    _limit: 10,
    page: 2
  },
  loadingMessage: 'Loading posts from JSON Placeholder...'
})(Component)

Hastimeouts

Не ожидает никаких параметров и возвращает обернутой компонент с инъекционными реквизитами addimeout и Clearimeouts Отказ Эти реквизиты позволяют легко создавать тайм-ауты и иметь возможность очистить их, когда компонент размонтирует. Если у вас есть активное время ожидания и размонтируйте компонент, он бросит ошибку.

const hasTimeouts = WrappedComponent => {
  class HasTimeouts extends React.Component {
    constructor(props) {
      super(props)
      this.timeouts = []
      this.addTimeout = this.addTimeout.bind(this)
      this.clearTimeouts = this.clearTimeouts.bind(this)
    }

    addTimeout(func, delay) {
      this.timeouts.push(setTimeout(func, delay))
    }

    clearTimeouts() {
      this.timeouts.forEach(clearTimeout)
    }

    render() {
      return (
        
      )
    }
  }

  return HasTimeouts
}

Использовать:

hasTimeouts(Component)

islist

Ожидает одного параметра Тип который диктует классное значение, используемое в обернутом Div для списка. Этот HOC ожидает, что компонент списка имеет принцип данных, который содержит массив элементов. Все свойства отдельных предметов вводятся как реквизит для отдельного обернутого компонента.

Использовать:

isList('component-type')(Component)

Композиция с использованием компонентов высшего порядка

Истинная мощность HOCS приходит, когда вы начинаете цепь (составляют) их. Вы можете цепить как многие из них, как вам нравится. Если у вас есть компонент, который нуждается в ошибке и состоянии по умолчанию, просто составляйте это так:

compose(
  hasError(ErrorComponent),
  hasDefault(DefaultComponent)
)(Component)

Возвращенный компонент теперь можно контролировать, чтобы показать ошибку или по умолчанию, используя его реквизиты. В случае из приведенного выше примера, если использование Deadefault и HaseRor являются оба правда , Haserror и Errorcomponent пройдет прецедент, поскольку он сначала входит в составную функцию.

Хотите добавить вход в список вышеуказанного компонента, а также поставляйте его с помощью Mockdata? Легкий! Просто измените вышеизложенное на:

compose(
  hasLogger(),
  hasMockData(mockData, delay),
  hasError(ErrorComponent),
  hasDefault(DefaultComponent)
)

HOCS может быть легко добавлен и составлен для расширения функциональности любого компонента.

iscontainer.

Ожидает единого объекта параметра с реквизитом данные , Ошибка . и Defaultcomponent Отказ данные Ожидается, что объект параметра, ожидаемый по Хашата HOC. Ошибка . Ожидается, что пользовательский компонент ошибок, но если оставить пустым, отобразит компонент ошибки по умолчанию. Defaultcomponent Ожидается, что компонент отображается в списке контейнера, если из API не было извлечено никаких элементов.

const isContainer = ({data, Error, DefaultComponent}) => WrappedComponent => {
  const IsContainer = props => 

  return compose(
    hasData(data),
    hasLoader,
    hasError(Error),
    hasDefault(DefaultComponent)
  )(IsContainer)
}

Использовать:

isContainer({
  data: {
    url: 'https://jsonplaceholder.typicode.com/posts', 
    params: {
      page: 2,
      _limit: 10
    },
    loadingMessage: "Loading Posts..."
  },
  DefaultComponent: PostDefault
})(PostList)

Быстрая отметка о отладке

Для целей отладки мы делаем наш код немного более многословным. Используя HAPPROPS HOC в качестве примера, мы могли бы еще больше упростить его так:

const hasProps = injectedProps => 
  WrappedComponent => props => 

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

Использование Redux Compose

Как упомянуто выше, Redux поставляет метод COMPOSE, который можно импортировать и использовать так:

import { compose } from 'redux'

compose(
    // ...do stuff
)(Component)

Вы можете прочитать больше об их реализации в их документации здесь Отказ Составная функция не очень особенная сама по себе, она может быть импортирована из многих библиотек.

Главная страница

Приведенное примерное приложение показывает использование всех концепций выше. Главная страница включает в себя компоненты, которые были расширены с HOCS, а также включает в себя кнопки для управления реквизитами, которые управляют HOCS, используемыми для их расширения. Чтобы просто поставить его, вы можете нажать кнопку и переключить, какую компонент рендерирует на основе реквизитов. Эта страница включает в себя MockPostContainer который расширяет Пост Компонент с регистратором, издевательствами, погрузчик, ошибка, по умолчанию и списку.

Сообщения, TODOS, комментарии и страницы пользователей

Все эти страницы потребляют реальные конечные точки API от здесь Отказ Каждый из них расширяет один компонент (пост, тоду, комментарий, пользователь) с iscontainer и islist HOCS.

Обертывание

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

Если вам нравится этот пост и нужна помощь с проблемой или искала нанимать фрилансера, я доступен для реагирования, Redux и JavaScript!