Skip to content

Instantly share code, notes, and snippets.

@zmts
Last active March 17, 2021 14:43
Show Gist options
  • Select an option

  • Save zmts/b91f2311048749b9cdef78553f18d608 to your computer and use it in GitHub Desktop.

Select an option

Save zmts/b91f2311048749b9cdef78553f18d608 to your computer and use it in GitHub Desktop.
Про состояние компонентов Vue.js и где его держать.

FLUX vs noFLUX in Vue.js

Жил был разработчик. Писал он себе кодяру на Vue.js и горя не знал, пока черти не дернули его более внимательно прочитать доку по VUEX. И увидел он там волшебное слово FLUX.

Про состояние компонентов Vue.js и где его держать.

Обычно при разработке приложений придерживаюсь принципа:

  • Все данные которые относятся непосредственно компоненту храним непосредственно в нем
  • Global/Shared данные в стор
  • Как вариант разделать stateless и stateful компоненты

На пример у нас есть простенькая страничка со списком айтемов и нам необходимо его отрисовать. Я создаю компонент pages\news\NewsPage.vue и pages\news\NewsItem.vue.

В первом обращаюсь к АПИ, сохраняю список айтомов, меняю статусы(loading/error). Все в одном компоненте(файле). Второй принимает через проп айтем и отрисовывает его. Все! Далее для дебага юзаем как обычно VueDevTools и не знаем горя.

Но у FLUX'а на эту задачу немного другой ответ. И так рассмотрим тот же пример с двумя компонентами. Для реализации данного ф-ционала нам понадобится взаимодействовать с пятью абстракциями:

  • State module store
  • Action
  • API call
  • Mutation
  • Getter

В action через api call фетчим данные >> записываем данные в стор через mutation. При этом зачастую для каждой сущности(доменной группы сущностей) в сторе создается отдельный модуль и в каждом модуле лежит 4-5 js файлов (actions.js, mutations.js ...).

Для фетча данных выходит такой путь DISPATCH >> ACTION >> API_CALL >> MUTATION >> GETTER. Для отображение какого нибудь loading статуса, необходимо пройти$store >> someModuleState >> loading ну да или воспользоваться вспомогательной ф-цией mapState. Вместо this.loading. А как быть с формочками тоже прикажите хранить эти все чекбоксы/инпуты в сторе ?

При таком раскладе каждый разработчик трактует по своему как разделять данные. Это в стор/это в локальное состояние компонента. У каждого свой FLUX.

А все это делается что бы придерживаться принципа одностороннего изменения данных. Компонент не должен знать как менять данные итд. Что в итоге деет свои плюшки при поддержке и дебаге приложения. А если сюда еще добавить еще и функциональщину и иммутабельность... все ховайся... А по факту в большинстве случаев(я не обобщаю.) все как дебажили консоллогом так и дебажат. Периодически заглядывая в VueDevTools.

Внимание вопрос!

В контексте React приложений своя атмосфера и оно там к месту.

  • К месту ли такие танцы в контексте Vue ?
  • Стоит ли овчинка выделки ?
  • Как понимать что хранить в сторе а что в локальном состоянии компонента ? Статусы (error/loading), филды формочек, чекбоксы... это все куда ?

Если вам есть что сказать буду рад обсудить в комментах.

p.s.

@zmts
Copy link
Author

zmts commented May 15, 2018

@xanf Большое спасибо за развернутый ответ!

@sp1ker
Copy link

sp1ker commented May 16, 2018

Vuex слишком нагромождён для мелких проектов и несвязанных страниц. Но сам FLUX это не только Vuex. Можно написать свой с блекджеком и однопоточными данными.
Где Vuex может быть не очень:

  1. Страницы, которые работают сами по себе и никак между собой не связаны. Например, при разработке компонента CRUD для всех таблиц БД я не использовал Vuex. Без него всё получилось чистым и с куда меньшим количеством кода, т.к. каждая страница и каждая сущность не связана ни с чем, кроме самой себя. Для обычного REST без кеширования в самый раз.
  2. Модальные окна. Управлять состоянием модальных окон через Vuex такое себе удовольствие. Окна могут создаваться динамически, они могут открываться друг в друге 5 раз. Где-то всё это нужно хранить. Локальное состояние тут в самый раз.
  3. Выводы всяких ошибок. Опять же, нам не нужно хранить это всё во Vuex. ошибку может генерировать Api-метод, который просто инициализирует динамически компонент и прокидывает ему код ошибки с текстом. Vuex тут наоборот запутает добавлением нового модуля или замусориванием главного хранилища.

Где Vuex отлично подходит:

  1. У вас очень много сущностей, например, User, Post, Comment, Rate и многое другое. Они все очень сильно связаны и изменение одной сущности влияет на всё остальное. В этом случае компоненты перестают задумываться о том, откуда данные пришли и как они обновились. За это отвечает хранилище. А компоненты просто получают эти данные и реактивно всё обновляют.
  2. SPA/PWA. Почти всё, что и в первом случае. Много зависимостей + страницы живут очень долго.

Сам по себе FLUX как архитектурный стиль очень хорош. Можно писать свои аналоги Vuex со своими киллер-фичами, которые требуются именно вам и вашему проекту. Но в вебе без него сейчас сложно что-то делать. По своему существу FLUX похож на обычные события, но только всё проходит централизованно, более точечно и декларативно.

У себя использую гибридный подход. Что-то очень хорошо подходит под локальные состояния, что-то под Vuex. В любом случае, если что-то у меня используется в одном месте, а потом понадобилось вынести во Vuex, это сделать очень просто.

@zmts
Copy link
Author

zmts commented May 16, 2018

@sp1ker Круто! Спасибо!

@akleandrov
Copy link

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

@igogrek
Copy link

igogrek commented Sep 10, 2018

Практически полностью согласен с @xanf, поэтому не буду вдаваться в подробности, а просто приведу наш опыт и несколько примеров.

Мы сделали пару проектов используя"чистый" store с попыткой выносить туда все данные, как только они появляются. То есть не использовать локальную data вовсе, дабы потом сэкономить время на перенос из data в store. В конечном итоге, вся эта красивость и чистота кода большой пользы нам не принесла, а размер стора вырос весьма существенно.
Особенно плохо это работало для случаев когда данные как раз зависят от жизненного цикла компонента. С локальной датой хуки прекрасно очищают ее в момент уничтожения компонента, а со стором это вовсе не так удобно.

В итоге для себя мы выбрали смешанный подход:

  1. data используется всегда по умолчанию до тех пор пока необходимо использовать одни и те же данные в 2+ компонентах/страницах.
    Принципиально не используем в таких случаях передачу данных через props ниже по дереву компонентов.
  2. Только data всегда используется в простых переиспользуемых компонентах, вроде чекбоксов, селектов, таблиц и т.д.,
    • за исключением случаев, когда компоненты состоят из большого количества подкомпонентов (когда они подпадают под пункт 1), тогда у корневого компонента появляется свой собственный стор
  3. Всегда используем геттеры для обращения к полям стора
  4. Используем ACTION'ы только если это асинхронные операции или комбинации большого количества мутаций, а так же в случае если необходимо одну операцию выполнять из 2+ компонентов

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment