Как синхронизировать состояние Redux и параметры хэш-тега url

У нас есть список лекций и глав, где пользователь может выбрать и отменить выбор. Два списка хранятся в хранилище redux. Теперь мы хотим сохранить представление выбранных заголовков лекций и заголовков глав в хэш-теге URL-адреса, и любые изменения URL-адреса также должны изменить хранилище (двусторонняя синхронизация).

Каким будет лучшее решение с использованием response-router или даже response-router-redux?

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


person JoKer    schedule 19.04.2016    source источник
comment
Почему вы хотите сохранить это состояние в магазине, а не просто использовать React Router в качестве источника истины для параметров URL и использовать реквизиты, которые он вводит в ваш mapStateToProps (state, ownProps)?   -  person Dan Abramov    schedule 19.04.2016
comment
Потому что параметры url содержат только заголовки лекций и выбранных глав. В магазине у меня есть список лекций и глав с именем, заголовком и выбранным логическим значением.   -  person JoKer    schedule 20.04.2016
comment
например использовать peterbeshai.com/react-url-query?   -  person mb21    schedule 06.03.2018


Ответы (2)


Думаю, в этом нет необходимости.
(Извините за пренебрежительный ответ, но это лучшее решение в моем опыте.)

Магазин - это источник правды для ваших данных. Это нормально.
Если вы используете React Router, пусть он будет источником истины для состояния вашего URL.
Вам не нужно хранить все в магазине.

Например, учитывая ваш вариант использования:

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

Проблема в том, что вы дублируете данные. Данные в магазине (chapter.selected) дублируются в состоянии React Router. Одно из решений - синхронизировать их, но это быстро усложняется. Почему бы просто не позволить React Router стать источником истины для выбранных глав?

Тогда состояние вашего магазина будет выглядеть (упрощенно):

{
  // Might be paginated, kept inside a "book", etc:
  visibleChapterSlugs: ['intro', 'wow', 'ending'],

  // A simple ID dictionary:
  chaptersBySlug: {
    'intro': {
      slug: 'intro',
      title: 'Introduction'
    },
    'wow': {
      slug: 'wow',
      title: 'All the things'
    },
    'ending': {
      slug: 'ending',
      title: 'The End!'
    }
  }
}

Вот и все! Не храните там selected. Вместо этого позвольте React Router справиться с этим. В обработчике маршрута напишите что-нибудь вроде

function ChapterList({ chapters }) {
  return (
    <div>
      {chapters.map(chapter => <Chapter chapter={chapter} key={chapter.slug} />)}
    </div>
  )
}

const mapStateToProps = (state, ownProps) => {
  // Use props injected by React Router:
  const selectedSlugs = ownProps.params.selectedSlugs.split(';')

  // Use both state and this information to generate final props:
  const chapters = state.visibleChapterSlugs.map(slug => {
    return Object.assign({
      isSelected: selectedSlugs.indexOf(slug) > -1,
    }, state.chaptersBySlug[slug])
  })

  return { chapters }
}

export default connect(mapStateToProps)(ChapterList)
person Dan Abramov    schedule 20.04.2016
comment
Спасибо @dan за подробный ответ. Постараюсь применить и расскажу, как это работало. - person JoKer; 22.04.2016
comment
извините, что вернулся так поздно, но на прошлой неделе я был в отпуске. У меня есть один вопрос. Вы описали один способ получения данных с URL-адреса и их рендеринга. Как бы вы обновили URL-адрес, добавив в него новые выбранные главы? - person JoKer; 02.05.2016
comment
Я бы назвал browserHistory.push() (где browserHistory импортирован из react-router) в создателе действий. Я бы, вероятно, использовал Redux Thunk, чтобы прояснить, что происходит побочный эффект. Я бы позвонил в него dispatch({ ... }); browserHistory.push(...). - person Dan Abramov; 02.05.2016
comment
Привет, Дэн. Спасибо за Redux! Мой я тоже свои 2 цента поставил в тему и задаю вопрос. Что, если логика перехода между состояниями приложения зависит от данных в запросе? Это означает, что редукторам он нужен, и вы не можете просто избавиться от него в магазине. - person Alexander Reshytko; 07.05.2016
comment
@AlexanderReshytko Поскольку эти данные поступают из «внешнего мира», я отправляю с ними действия при необходимости. Это не означает, что вам нужно общее действие «Маршрут изменен» (даже если вы можете отправить его, если сочтете его полезным). Затем ваши редукторы могут использовать эту информацию, как обычно. - person Dan Abramov; 08.05.2016
comment
Немного неудобно отправлять параметры для повторного выбора селекторов, поэтому возможность получить текущие параметры URL-адреса из магазина очень полезна. - person Jacob Rask; 17.05.2016
comment
@DanAbramov, спасибо за ответ, но я не понимаю! Как вы можете делать что-то (например, отправлять действия), если данные URL-адреса доступны только в маршрутизаторе? Представьте, что вы создаете простой чат и в хеш URL указываете имя чата. Вы загружаете приложение с # / some-fun-room в URL-адресе. Как вы можете отправить действие для подключения к комнате? Я вижу, как люди отправляют вещи из компонентов ... мне это кажется совершенно неправильным. - person lud; 06.01.2017
comment
@DanAbramov Что касается вашего первого комментария, могу я спросить, что бы вы пропустили в dispatch? Зачем это нужно? Спасибо! - person Ioan; 08.03.2017
comment
Ваш mapStateToProps создает новый объект в свойстве chapters возвращаемых свойств. Это приведет к повторной визуализации компонента каждый раз, когда что-либо в магазине изменяется (потому что одно из свойств изменяется при каждом действии redux). - person krzychek; 07.06.2017

react-router-redux может помочь вам добавить URL-адрес для хранения, поэтому каждый раз, когда хэш-тег изменяется, сохраняйте его.

person David Guan    schedule 20.04.2016
comment
Он просто дает вам местоположение, а не проанализированные параметры, поэтому его полезность ограничена, если вы не готовы повторно реализовать то, что React Router дает вам вручную. Это хорошее решение для синхронизации хранилища с действиями , чтобы запись и воспроизведение сеансов пользователей работали, но на самом деле это не так полезно для приложений, которым это не нужно. - person Dan Abramov; 20.04.2016