В приложении Flux должен быть только один диспетчер. Все данные проходят через этот центральный узел. Наличие одноэлементного диспетчера позволяет ему управлять всеми магазинами. Это становится важным, когда вам нужно само обновление Store # 1, а затем само обновление Store # 2 на основе как действия, так и состояния Store # 1. Flux предполагает, что такая ситуация возможна в большом приложении. В идеале такой ситуации не должно быть, и разработчики должны стараться избегать этой сложности, если это возможно. Но одноэлементный Dispatcher готов с этим справиться, когда придет время.
Магазины тоже одиночные. Они должны оставаться как можно более независимыми и изолированными - это замкнутая вселенная, которую можно запрашивать из представления контроллера. Единственный путь в Магазин - это обратный вызов, который он регистрирует в Диспетчере. Единственный выход - через функции получения. Магазины также публикуют событие, когда их состояние изменилось, поэтому Controller-Views могут знать, когда запрашивать новое состояние, используя методы получения.
В вашем примере приложения будет один файл PostStore
. Этот же магазин может управлять сообщениями на «странице» (псевдостранице), которая больше похожа на новостную ленту FB, где сообщения появляются от разных пользователей. Его логический домен - это список сообщений, и он может обрабатывать любой список сообщений. Когда мы переходим от псевдостраницы к псевдостранице, мы хотим повторно инициализировать состояние хранилища, чтобы отразить новое состояние. Мы также могли бы захотеть кэшировать предыдущее состояние в localStorage в качестве оптимизации для перемещения назад и вперед между псевдостраницами, но я бы хотел создать объект PageStore
, ожидающий всех других хранилищ, управляющий отношениями с localStorage для всех хранилищ на псевдостраницу, а затем обновляет свое состояние. Обратите внимание, что это PageStore
ничего не будет хранить о сообщениях - это доменPostStore
, Он просто будет знать, кэширована ли конкретная псевдостраница или нет, потому что псевдостраницы являются ее доменом.
У них PostStore
был бы initialize()
метод. Этот метод всегда очищает старое состояние, даже если это первая инициализация, а затем создает состояние на основе данных, полученных через Action, через Dispatcher. Переход с одной псевдостраницы на другую, вероятно, потребует PAGE_UPDATE
действия, которое вызовет вызов initialize()
. Есть детали, которые нужно проработать вокруг извлечения данных из локального кеша, извлечения данных с сервера, оптимистичного рендеринга и состояний ошибок XHR, но это общая идея.
Если для конкретной псевдостраницы не нужны все хранилища в приложении, я не совсем уверен, что есть какая-то причина для уничтожения неиспользуемых, кроме ограничений памяти. Но магазины обычно не потребляют много памяти. Вам просто нужно убедиться, что вы удалили прослушиватели событий в уничтожаемых вами представлениях контроллера. Это делается в componentWillUnmount()
методе React .
UserListStore
со всеми соответствующими пользователями. И у каждого пользователя будет пара логических флагов, описывающих отношение к текущему профилю пользователя. Что-то вроде{ follower: true, followed: false }
, например. МетодыgetFolloweds()
иgetFollowers()
будут получать различные наборы пользователей, необходимые для пользовательского интерфейса.(Примечание: я использовал синтаксис ES6 с опцией JSX Harmony.)
В качестве упражнения я написал образец приложения Flux, которое позволяет просматривать
Github users
и делать репозитории.Он основан на ответе fisherwebdev, но также отражает подход, который я использую для нормализации ответов API.
Я сделал это, чтобы задокументировать несколько подходов, которые я пробовал при изучении Flux.
Я старался сделать это ближе к реальному миру (разбивка на страницы, никаких поддельных API localStorage).
Здесь есть несколько моментов, которые меня особенно интересовали:
switch
с действиями ;Как я классифицирую магазины
Я попытался избежать дублирования, которое видел в другом примере Flux, особенно в магазинах. Я счел полезным разделить магазины на три категории:
Хранилища содержимого содержат все объекты приложений. Все, что имеет идентификатор, нуждается в собственном Content Store. Компоненты, отображающие отдельные элементы, запрашивают свежие данные в хранилищах содержимого.
Магазины контента собирают свои объекты в результате всех действий сервера. Например,
UserStore
проверяет,action.response.entities.users
существует ли он, независимо от того, какое действие было запущено. Нет необходимости вswitch
. Normalizr упрощает преобразование любых ответов API в этот формат.Хранилища списков отслеживают идентификаторы сущностей, которые появляются в некотором глобальном списке (например, «лента», «ваши уведомления»). В этом проекте у меня таких магазинов нет, но я подумал, что все равно их упомяну. Они обрабатывают нумерацию страниц.
Как правило , они реагируют на всего несколько действий (например
REQUEST_FEED
,REQUEST_FEED_SUCCESS
,REQUEST_FEED_ERROR
).Индексированные списковые магазины похожи на списковые магазины, но они определяют отношение «один ко многим». Например, «подписчики пользователя», «звездочеты репозитория», «репозитории пользователя». Они также обрабатывают нумерацию страниц.
Кроме того, они обычно реагируют на всего лишь несколько действий (например
REQUEST_USER_REPOS
,REQUEST_USER_REPOS_SUCCESS
,REQUEST_USER_REPOS_ERROR
).В большинстве социальных приложений их будет много, и вы захотите быстро создать еще одно.
Примечание: это не настоящие классы или что-то в этом роде; именно так мне нравится думать о магазинах. Но я сделал несколько помощников.
StoreUtils
createStore
Этот метод дает вам самый простой магазин:
Я использую его для создания всех магазинов.
isInBag
,mergeIntoBag
Маленькие помощники, полезные для магазинов контента.
PaginatedList
Сохраняет состояние разбивки на страницы и обеспечивает выполнение определенных утверждений (невозможно получить страницу во время выборки и т. Д.).
PaginatedStoreUtils
createListStore
,createIndexedListStore
,createListActionHandler
Делает создание индексированных хранилищ списков настолько простым, насколько это возможно, за счет предоставления шаблонных методов и обработки действий:
createStoreMixin
Примесь, которая позволяет компонентам настраиваться на интересующие их магазины, например
mixins: [createStoreMixin(UserStore)]
.источник
Таким образом, в Reflux отсутствует концепция диспетчера, и вам нужно думать только о потоке данных через действия и хранилища. Т.е.
Каждая стрелка здесь моделирует, как прослушивается поток данных, что, в свою очередь, означает, что данные идут в противоположном направлении. Фактическая цифра для потока данных такова:
В вашем случае использования, если я правильно понял, нам нужно
openUserProfile
действие, которое инициирует загрузку профиля пользователя и переключение страницы, а также некоторые действия по загрузке сообщений, которые будут загружать сообщения при открытии страницы профиля пользователя и во время события бесконечной прокрутки. Итак, я предполагаю, что в приложении есть следующие хранилища данных:В Reflux вы бы настроили это так:
Действия
Магазин страниц
Магазин профилей пользователей
Магазин сообщений
Компоненты
Я предполагаю, что у вас есть компонент для просмотра всей страницы, страницы профиля пользователя и списка сообщений. Необходимо подключить следующее:
Action.openUserProfile
с правильным идентификатором во время события нажатия.currentPageStore
чтобы знать, на какую страницу переключиться.currentUserProfileStore
чтобы знать, какие данные профиля пользователя отображать.currentPostsStore
чтобы получать загруженные сообщенияAction.loadMorePosts
.И это должно быть все.
источник