Реакция: загрузка и обновление вложенных ресурсов при изменении URI без избыточного дублирования? - PullRequest
0 голосов
/ 14 сентября 2018

Допустим, у меня есть вложенная структура URI, что-то вроде следующего:

http://example.com/collections/{id}

http://example.com/collections/{collectionId}/categories/{id}

http://example.com/collections/{collectionId}/categories/{categoryId}/book/{id}

Я могу использовать react-router для визуализации правильного компонента при загрузке страницы и при изменении URI.

Давайте рассмотрим первый случай:

http://example.com/collections/{id}

Предположим, у нас есть компонент CollectionShow.

Когда компонент загружается впервые, я могу извлечь идентификатор коллекции из URI и загрузить правильную коллекцию:

componentDidMount () {
  this.loadCollection(this.props.match.params.id);
}

(Предположим, что loadCollection загружает коллекцию вызовом AJAX и устанавливает ее в состояние компонента.)

Однако, когда изменяется URI (например, пользователь нажимает на<Link>, react-router не полностью перестраивает компонент, он просто обновляет его реквизиты, заставляя его перерисовываться, поэтому для обновления состояния компонента нам также необходимо обновить состояние при обновлении:

componentDidUpdate(prevProps) {
  if (!this.state.collection || this.collectionDidChange(prevProps)) {
    this.loadCollection(this.props.match.params.id);
  }
}

collectionDidChange(prevProps) {
  return String(prevProps.match.params.id) !== String(this.props.match.params.id)
}

Пока все хорошо. А как насчет второго URL?

http://example.com/collections/{collectionId}/categories/{id}

Давайте предположим, что у нас есть компонент CategoryShow.

Теперь нам нужно учитывать не только изменение collectionId, но и идентификатор категории.Мы должны перезагрузить коллекцию, если этот идентификатор изменится, и мы также должны перезагрузить категорию, если , что изменится.

Проблема связана с вложенностью третьего уровня (компонент BookShow).В итоге получается что-то вроде этого:

componentDidUpdate(prevProps) {
  if (!this.state.collection || this.collectionDidChange(prevProps)) {
    this.loadCollection(this.props.match.params.collectionId);
  }

  if (!this.state.category || this.collectionDidChange(prevProps) || this.categoryDidChange(prevProps)) {
    this.loadCollection(this.props.match.params.collectionId)
        .then(() => this.loadCategory(this.props.match.params.categoryId);
  }

  if (!this.state.book || this.collectionDidChange(prevProps) || this.categoryDidChange(prevProps) || this.bookDidChange(prevProps)) {
    this.loadCollection(this.props.match.params.collectionId)
        .then(() => this.loadCategory(this.props.match.params.categoryId)
        .then(() => this.loadBook(this.props.match.params.id);
  }
}

Это не только громоздко, но и приводит к значительному дублированию кода во всех трех компонентах: CollectionShow, CategoryShow и BookShow.

Использование приставки не сильно поможет, потому что нам все еще нужно обновлять глобальное состояние при изменении URI.

Существует ли чистый, эффективный и удобный для реагирования способ обработки обновленийвложенные ресурсы, подобные этим?

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

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

  • Код, которым вы поделились, будет разделен на 3 других
  • Метод mponentDidUpdate (prevProps) просто перейдет к родительскому компонентуas componentDidMount ().
  • Тогда, если маршрутизатор изменится, компонент будет воссоздан, и новые значения будут отправлены по модулям.
  • Если вы не хотите разделять свой код, вы должны по крайней меревыполните шаг 2.

//everytime you get to the router this will be triggered and depending of the parameters of your router, you get the values you need and set the state
componentDidMount() {
  if (!this.state.collection) {
    this.loadCollection(this.props.match.params.collectionId);
  }

  if (!this.state.category) {
    this.loadCollection(this.props.match.params.collectionId)
        .then(() => this.loadCategory(this.props.match.params.categoryId);
  }

  if (!this.state.book) {
    this.loadCollection(this.props.match.params.collectionId)
        .then(() => this.loadCategory(this.props.match.params.categoryId)
        .then(() => this.loadBook(this.props.match.params.id);
  }
}


render() {
  return (
    //you can add conditions to render as well
    <CollectionComponent {...this.props} {...{
        collection: this.collection
    }} />
    <CategoryComponent {...this.props} {...{
        categ: this.categ
    }} />
    <BookComponent {...this.props} {...{
        book: this.book
    }} />
  )
}
0 голосов
/ 17 сентября 2018

Вы можете создать компонент CollectionPage, который обрабатывает все вызовы AJAX и сохраняет данные в состоянии. Это может передать collection, category / categories и books компонентам (CollectionShow, CategoryShow и BookShow).

В CollectionPage вы можете использовать componentDidUpdate и componentDidMount в том виде, в каком вы их представили.

Ваши <*>Show компоненты ничего не будут знать о props.match.params.* и получат только данные, необходимые для рендеринга нужного контента.

CollectionPage можно использовать для всех ваших маршрутов или вы можете изменить маршрут на что-то вроде

/collections/:collectionId?/:categoryId?/:bookId?

создание всех параметров params. Вы можете проверить доступные идентификаторы в CollectionPage.

Надеюсь, это поможет!

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