Как стать автором
Обновить

Комментарии 19

> Такое использование геттеров встречается достаточно часто и это плохо.

А почему плохо, я так и не понял. Я лично делаю геттер и вот почему: стэйт обычно нужен когда несколько компонентов работают с одними данными, и геттер лучше будет в одном месте а не в нескольких компонентах. Создаю его я даже если он только в одном уомпоненте используется, и отчасти не потому что «пусть будет, мало ли какой новый компонент его потребует», а потому что его сделал, добавил в юнит тест стораджа и забыл.
...mapGetter(['films']),

выглядит точно так же красиво как
...mapState(['films']),


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

По третеьему пункту соглашусь. Геттеры с параметрами это боль. Особенно тестирование.
Я думаю, что достаточно радикально выразил свои мысли. В данном случае имелось ввиду, что такое использование геттеров вызывает просто дублирование кода, чаще всего так и получается на практике. Но если такое использование геттеров удовлетворяет какие-то архитектурные запросы в проекте, то почему нет. По второму пункту, это мое личное мнение в плане переносимости логики. Например в моей практике есть примеры переиспользования бизнес логики из хранилища в других проектов, которые работают в рамках одной системы, поэтому выносить частное применение чего-либо в общее хранилище может быть неправильным. Например аналогичная ситуация происходит с экшенами, разработчики превращают их в место хранения обращений к апи, это тоже оверюзное использование стора. Опять таки, это рекомендации начинающим разработчикам, со временем люди нарабатывают свой опыт и уже сами находят удобное для себя использование.

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

Я думаю одним из вариантов является создать api factory, например как тут link.medium.com/EtLkVqMC7X. Такой вариант позволяет отделить генератор апи обращений и их хранение. Затем вы просто обращается к ним из нужного вам место. Просто нужно помнить, что если апи не является порождающим глобальные изменения и его вызов нужен только единожды для какого-то простого действия, то не выносите его в стор, точно так же, как не нужно тащить в стор флаги заугрузки, да, это удобно, но всё таки это логика компонента.
Соглашусь, что в случае необходимости данных только внутри компонента, хранить эти данные (а если их еще и мутировать надо — то это еще и дополнительные экшены/мутации) в сторе — это оверхед. У меня реализация примерно такая же, как вы и предложили, единственное что у меня не фабрика, а файл с набором методов-промисов, которые я импортирую в стор если это нужно хранить глобально, либо, если это «локальные нужды» компонента, то импортирую метод прямо в компонент и там работаю с результатом. Надо будет задуматься над преимуществами реализации в виде фабрики…

С флагами тоже поддерживаю, а ведь именно так раньше я и делал. Управление флагами загрузки оказалось гораздо более гибким и очевидным если оно реализовано внутри компонента, а не стора.
А можете объяснить зачем вообще использовать гетеры или компютед методы когда и одно и другое скорее для формата данных или какой то постобработки, а просто пробрасывать лишнее действие, операция чтения из стейта безопасна и можно использовать то что нужно прямо в шаблоне.
<li v-for="(film,index) in $store.state.films" :key=index>
    {{film.title}}
</li>
Ну тут скорее вопрос аккуратности написанного кода. Когда я вижу в коде такое обращение к state — это не очень удобно, так как скорее всего для сложного фильтра у вас mapState или геттер в компьтед, а для простого вы дергаете в темплейте $store.state.films, то это выглядит громоздко, особенно если нас в какой-то момент понадобится отфильтровать вывод по какому-то параметру, то придётся вносить гораздо больше изменений.
В вашем примере это можно использовать и так, как вы написали, разве что страдает чистота кода. Но если пример будет более сложный и геттер используется в нескольких компонентах, то при смене структуры хранилища, нужно будет изменить путь только в одном геттере, а не искать все компоненты, в которых путь был «прибит гвоздями». Тестирование так же усложнится.
А что если геттер для получения свойства из state используется в разных компонентах? Каждый раз делать computed property? Мне кажется что всё-таки сделать его глобальным будет лучше в таком случае.
Вы точно также можете использовать само свойство, оо есть по сути вы будете в каждом компоненте работать с mapState. Либо делать return this.$store.state.stateName, что не очень красиво. Когда вы делаете геттер, то накладываете ещё один слой кода, делать это для простого действия не очень хорошо, это размазывает логику по коду, особенно если вы храните state, mutations, actions и getters в разных файлах.
Спасибо за пояснение. Просто в моем случае во vuex лежат только глобальные данные (после инициализации приложения, например имя пользователя) и свойства нужно дергать одинаково в очень многих местах. На мой взгляд удобнее иметь глобальный геттер в этом случае, чем делать 10 совершенно идентичных computed property в разных местах.

Или в этом случае кошернее будет обращаться к $store.state.* напрямую?
Я так понимаю у вас геттер, который собирает имя пользователя мз двух полей, то да, ну или он возвращает user.name. Но если вы в сторе держите напрямую поле userName, то лучше делать ...mapState(‘userName’). Разработчики, которые будут поддерживать код после вас скажут вам спасибо)
Но если вы в сторе держите напрямую поле userName, то лучше делать ...mapState(‘userName’). Разработчики, которые будут поддерживать код после вас скажут вам спасибо)

Вы снова не ответили на вопрос чем это лучше.

А если понадобится поменять имя поля? Искать все кейсы с mapstate или один раз в одном геттере изменить.
Если честно, причина достаточно сомнительная, так как если у вас в проекте происходит такое глобальное изменение, то скорее всего имя геттера тоже должно быть застронуто. Если вы условно изменили userName на nickName, но геттер остался с тем же именем, то это вызовет как минимум недоумение у других разработчиков.
У меня, например, в сторе хранится пользователь с полем, которое описывает его права:
user: {
  roles: ['IS_ADMIN', 'IS_COMPANY', 'IS_USER'],
  ...
}

В сторе у меня есть глобальный геттер, который определяет, является ли пользователь админом:
isAdmin() {
  return this.state.roles.includes(Roles.ROLE_ADMIN);
}
    .reduce((result, film) => ({
      ...result,
      [film.id]: film,
    }), {})

Вместо простого алгоритма наполнения хэша со сложностью O(n) получается n наполнений хэша общей сложностью O(n!). Создается n промежуточных объектов. В некоторых случаях это может создать большую нагрузку на GC, т.к. общее количество ключей во всех этих объектах тоже будет n!..
Такое будет работать быстро в функциональных языках, благодаря оптимизациям, которые возможны из-за других особенностей языка. В других языках, включая js, этих оптимизаций может не быть (скорее всего).
Подходы ФП могут сделать код читаемым и лаконичным. Хотя в этом примере страдает даже читаемость.

Соглашусь с вами.
getters: {
  filmsById: (state) => {
    const result = {};
    state.films.forEach((film) => {
      result[film.id] = film;
    });
    return result;
  },
},
const [film = {}] = state.films.filter(f => f.name === 'Джеймс Бонд');

Понятно, что это только пример, но все-таки правильнее использовать Array.find
const film = state.films.find(f => f.name === 'Джеймс Бонд') || {};
Да, думаю так будет правильнее.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории