Статьи

Как создавать сложные, масштабные приложения Vue.js с Vuex

Учиться и использовать Vue.js настолько легко, что любой может создать простое приложение с этой средой . Даже новички, с помощью документации Vue, могут сделать эту работу. Однако, когда в игру вступает сложность, все становится немного серьезнее. Правда состоит в том, что несколько глубоко вложенных компонентов с общим состоянием могут быстро превратить ваше приложение в неразрешимый беспорядок.

Основная проблема в сложном приложении заключается в том, как управлять состоянием между компонентами без написания спагетти-кода или создания побочных эффектов. В этом руководстве вы узнаете, как решить эту проблему с помощью Vuex : библиотеки управления состоянием для создания сложных приложений Vue.js.

Vuex — это библиотека управления состоянием, специально предназначенная для создания сложных крупномасштабных приложений Vue.js. Он использует глобальное централизованное хранилище для всех компонентов в приложении, используя преимущества своей системы реактивности для мгновенных обновлений.

Хранилище Vuex спроектировано таким образом, что невозможно изменить его состояние из какого-либо компонента. Это гарантирует, что состояние может быть изменено только предсказуемым образом. Таким образом, ваше хранилище становится единым источником правды: каждый элемент данных хранится только один раз и доступен только для чтения, чтобы предотвратить повреждение компонентами приложения состояния, к которому получают доступ другие компоненты.

Вы можете спросить: зачем мне Vuex? Разве я не могу просто поместить общее состояние в обычный файл JavaScript и импортировать его в свое приложение Vue.js?

Конечно, вы можете, но по сравнению с простым глобальным объектом, магазин Vuex имеет ряд существенных преимуществ и преимуществ:

  • Магазин Vuex реагирует. Как только компоненты извлекают из него состояние, они реактивно обновляют свои представления каждый раз, когда состояние изменяется.
  • Компоненты не могут напрямую изменять состояние магазина. Единственный способ изменить состояние магазина — это явно зафиксировать мутации. Это гарантирует, что каждое изменение состояния оставляет отслеживаемую запись, что облегчает отладку и тестирование приложения.
  • Вы можете легко отлаживать свое приложение благодаря интеграции Vuex с расширением Vue DevTools .
  • Магазин Vuex дает вам с высоты птичьего полета, как все связано и влияет на ваше приложение.
  • Проще поддерживать и синхронизировать состояние между несколькими компонентами, даже если иерархия компонентов изменяется.
  • Vuex делает возможным прямое межкомпонентное общение.
  • Если компонент уничтожен, состояние в хранилище Vuex останется без изменений.

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

Во-первых, чтобы следовать этому руководству, вы должны хорошо разбираться в Vue.js и его системе компонентов или, по крайней мере, иметь минимальный опыт работы с фреймворком.

Кроме того, цель этого руководства не в том, чтобы показать вам, как создать действительно сложное приложение; Цель состоит в том, чтобы сосредоточить ваше внимание на концепциях Vuex и на том, как вы можете использовать их для создания сложных приложений. По этой причине я собираюсь использовать очень простые и простые примеры без какого-либо избыточного кода. Как только вы полностью освоите концепции Vuex, вы сможете применять их на любом уровне сложности.

Наконец, я буду использовать синтаксис ES2015. Если вы не знакомы с этим, вы можете узнать это здесь .

А теперь давайте начнем!

Первым шагом для начала работы с Vuex является установка на вашем компьютере Vue.js и Vuex. Есть несколько способов сделать это, но мы будем использовать самый простой. Просто создайте HTML-файл и добавьте необходимые ссылки CDN:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
<head>
<meta charset=»UTF-8″ />
<!— Put the CSS code here —>
</head>
<body>
 
<!— Put the HTML template code here —>
 
<script src=»https://unpkg.com/vue»></script>
<script src=»https://unpkg.com/vuex»></script>
 
<script>
// Put the Vue code here
</script>
</body>
</html>

Я использовал немного CSS, чтобы компоненты выглядели лучше, но вам не нужно беспокоиться об этом коде CSS. Это только поможет вам получить визуальное представление о том, что происходит. Просто скопируйте и вставьте в тег <head> :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<style>
  #app {
    background-color: yellow;
    padding: 10px;
  }
  #parent {
    background-color: green;
    width: 400px;
    height: 300px;
    position: relative;
    padding-left: 5px;
  }
  h1 {
    margin-top: 0;
  }
  .child {
    width: 150px;
    height: 150px;
    position:absolute;
    top: 60px;
    padding: 0 5px 5px;
  }
  .childA {
    background-color: red;
    left: 20px;
  }
  .childB {
    background-color: blue;
    left: 190px;
  }
</style>

Теперь давайте создадим некоторые компоненты для работы. Внутри <script> , прямо над закрывающим </body> , поместите следующий код Vue:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Vue.component(‘ChildB’,{
  template:`
    <div class=»child childB»>
      <h1> Score: </h1>
    </div>`
})
 
Vue.component(‘ChildA’,{
  template:`
    <div class=»child childA»>
      <h1> Score: </h1>
    </div>`
})
 
Vue.component(‘Parent’,{
  template:`
    <div id=»parent»>
      <childA/>
      <childB/>
      <h1> Score: </h1>
    </div>`
})
 
new Vue ({
  el: ‘#app’
})

Здесь у нас есть экземпляр Vue, родительский компонент и два дочерних компонента. Каждый компонент имеет заголовок « Score: », в который мы выводим состояние приложения.

Последнее, что вам нужно сделать, это поместить перенос <div> с id="app" сразу после открытия <body> , а затем поместить родительский компонент внутрь:

1
2
3
<div id=»app»>
  <parent/>
</div>

Подготовительная работа завершена, и мы готовы двигаться дальше.

В реальной жизни мы имеем дело со сложностью, используя стратегии для организации и структурирования контента, который мы хотим использовать. Мы объединяем связанные вещи в разные разделы, категории и т. Д. Это похоже на библиотеку книг, в которой книги классифицируются и помещаются в разные разделы, чтобы мы могли легко найти то, что ищем. Vuex объединяет данные и логику приложения, связанные с состоянием, в четыре группы или категории: состояние, геттеры, мутации и действия.

Состояние и мутации являются основой для любого магазина Vuex:

  • state — это объект, который содержит состояние данных приложения.
  • mutations также объект, содержащий методы, которые влияют на состояние.

Получатели и действия подобны логическим проекциям состояния и мутаций:

  • getters содержат методы, используемые для абстрагирования доступа к состоянию и выполнения при необходимости некоторых заданий предварительной обработки (вычисление данных, фильтрация и т. д.).
  • actions — это методы, используемые для запуска мутаций и выполнения асинхронного кода.

Давайте рассмотрим следующую диаграмму, чтобы прояснить ситуацию:

Диаграмма рабочего процесса Vuex State Management

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

Чтобы изменить состояние, конкретный компонент Vue должен зафиксировать мутации (например, this.$store.commit('increment', 3) ), а затем эти мутации меняют состояние ( score становится 3 ). После этого геттеры автоматически обновляются благодаря реактивной системе Vue, и они отображают обновления в представлении компонента (с помощью this.$store.getters.score ).

Мутации не могут выполнять асинхронный код, потому что это сделает невозможным запись и отслеживание изменений в инструментах отладки, таких как Vue DevTools. Чтобы использовать асинхронную логику, вы должны поместить ее в действия. В этом случае компонент сначала отправит действия ( this.$store.dispatch('incrementScore', 3000) ), где выполняется асинхронный код, а затем эти действия передадут мутации, которые изменят состояние.

Теперь, когда мы изучили, как работает Vuex, давайте создадим скелет для нашего магазина Vuex. Поместите следующий код над регистрацией компонента ChildB :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
const store = new Vuex.Store({
  state: {
 
  },
  getters: {
 
  },
  mutations: {
 
  },
  actions: {
 
  }
})

Чтобы обеспечить глобальный доступ к хранилищу Vuex из каждого компонента, нам нужно добавить свойство store в экземпляр Vue:

1
2
3
4
new Vue ({
  el: ‘#app’,
  store // register the Vuex store globally
})

Теперь мы можем получить доступ к хранилищу из каждого компонента с помощью переменной this.$store .

Пока что, если вы откроете проект с CodePen в браузере , вы должны увидеть следующий результат.

App Skeleton

Объект состояния содержит все общие данные в вашем приложении. Конечно, при необходимости каждый компонент может иметь свое собственное частное состояние.

Представьте, что вы хотите создать игровое приложение, и вам нужна переменная для хранения игрового счета. Итак, вы положили его в объекте состояния:

1
2
3
state: {
  score: 0
}

Теперь вы можете получить доступ к баллу штата напрямую. Давайте вернемся к компонентам и повторно используем данные из магазина. Чтобы иметь возможность повторно использовать реактивные данные из состояния магазина, вы должны использовать вычисленные свойства. Итак, давайте создадим вычисляемое свойство Score score() в родительском компоненте:

1
2
3
4
5
computed: {
  score () {
    return this.$store.state.score
  }
}

В шаблоне родительского компонента поместите выражение {{ score }} :

1
<h1> Score: {{ score }} </h1>

А теперь сделайте то же самое для двух дочерних компонентов.

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

Конечно, хорошо, что вы можете повторно использовать ключевое слово this.$store.state внутри компонентов, как вы видели выше. Но представьте себе следующие сценарии:

  1. В крупномасштабном приложении, где несколько компонентов получают доступ к состоянию магазина с помощью this.$store.state.score , вы решаете изменить имя score . Это означает, что вы должны изменить имя переменной внутри каждого компонента, который ее использует!
  2. Вы хотите использовать вычисленное значение состояния. Например, допустим, вы хотите дать игрокам бонус в 10 баллов, когда счет достигнет 100 баллов. Таким образом, когда счет достигает 100 баллов, добавляется 10 бонусных очков. Это означает, что каждый компонент должен содержать функцию, которая повторно использует счет и увеличивает его на 10. У вас будет повторный код в каждом компоненте, что совсем не хорошо!

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

Давайте создадим score() :

1
2
3
4
5
getters: {
  score (state){
    return state.score
  }
}

Получатель получает state качестве первого аргумента, а затем использует его для доступа к свойствам состояния.

Примечание. Получатели также получают getters в качестве второго аргумента. Вы можете использовать его для доступа к другим получателям в магазине.

Во всех компонентах измените вычисляемое свойство score() чтобы использовать получатель score() вместо оценки состояния напрямую.

1
2
3
4
5
computed: {
  score () {
    return this.$store.getters.score
  }
}

Теперь, если вы решите изменить score на result , вам нужно обновить его только в одном месте: в получателе Score score() . Попробуйте это в этом CodePen!

Мутации являются единственным допустимым способом изменения состояния. Запуск изменений просто означает фиксацию мутаций в компонентных методах.

Мутация — это в значительной степени функция обработчика событий, которая определяется по имени. Функции обработчика мутаций получают state в качестве первого аргумента. Вы также можете передать дополнительный второй аргумент, который называется payload для мутации.

Давайте создадим мутацию increment() :

1
2
3
4
5
mutations: {
  increment (state, step) {
    state.score += step
  }
}

Мутации не могут быть вызваны напрямую! Чтобы выполнить мутацию, вы должны вызвать метод commit() с именем соответствующей мутации и возможными дополнительными параметрами. Это может быть только один, как step в нашем случае, или может быть несколько обернутых в объект.

Давайте использовать мутацию increment() в двух дочерних компонентах, создав метод changeScore() :

1
2
3
4
5
methods: {
  changeScore (){
    this.$store.commit(‘increment’, 3);
  }
}

Мы фиксируем мутацию вместо того, чтобы изменять this.$store.state.score напрямую, потому что мы хотим явно отслеживать изменения, сделанные мутацией. Таким образом, мы делаем логику нашего приложения более прозрачной, отслеживаемой и простой для анализа. Кроме того, это позволяет реализовать инструменты, такие как Vue DevTools или Vuetron , которые могут регистрировать все мутации, делать снимки состояния и выполнять отладку во времени.

Теперь давайте changeScore() метод changeScore() . В каждом шаблоне двух дочерних компонентов создайте кнопку и добавьте в нее прослушиватель события click:

1
<button @click=»changeScore»>Change Score</button>

Когда вы нажимаете кнопку, состояние увеличивается на 3, и это изменение будет отражаться во всех компонентах. Теперь мы эффективно достигли прямой межкомпонентной связи, что невозможно с помощью встроенного в Vue.js механизма «пропуска, событий вверх». Проверьте это в нашем примере CodePen .

Действие — это просто функция, которая совершает мутацию. Это косвенно изменяет состояние, что позволяет выполнять асинхронные операции.

Давайте создадим действие incrementScore() :

1
2
3
4
5
6
7
actions: {
  incrementScore: ({ commit }, delay) => {
    setTimeout(() => {
      commit(‘increment’, 3)
    }, delay)
  }
}

Действия получают context в качестве первого параметра, который содержит все методы и свойства из хранилища. Обычно мы просто извлекаем нужные нам части, используя деструктуризацию аргументов ES2015 . Метод commit нам нужен очень часто. Действия также получают второй аргумент полезной нагрузки, как мутации.

В компоненте ChildB измените метод changeScore() :

1
2
3
4
5
methods: {
  changeScore (){
    this.$store.dispatch(‘incrementScore’, 3000);
  }
}

Чтобы вызвать действие, мы используем метод dispatch() с именем соответствующего действия и дополнительными параметрами, как и с мутациями.

Теперь кнопка Изменить счет из компонента ChildA увеличит счет на 3. Аналогичная кнопка из компонента ChildB сделает то же самое, но с задержкой в ​​3 секунды. В первом случае мы выполняем синхронный код и используем мутацию, но во втором случае мы выполняем асинхронный код, и вместо этого нам нужно использовать действие. Посмотрите, как все это работает в нашем примере CodePen.

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

Вместо того, чтобы писать вычисляемое свойство Score score() следующим образом:

1
2
3
4
5
computed: {
  score () {
    return this.$store.state.score
  }
}

Мы просто используем помощник mapState() следующим образом:

1
2
3
computed: {
  …Vuex.mapState([‘score’])
}

И свойство score() создается автоматически для нас.

То же самое верно для добытчиков, мутаций и действий.

Чтобы создать получатель mapGetters() , мы используем помощник mapGetters() :

1
2
3
computed: {
  …Vuex.mapGetters([‘score’])
}

Чтобы создать метод changeScore() , мы используем помощник mapMutations() следующим образом:

1
2
3
methods: {
  …Vuex.mapMutations({changeScore: ‘increment’})
}

Когда используется для мутаций и действий с аргументом полезной нагрузки, мы должны передать этот аргумент в шаблон, где мы определяем обработчик события:

1
<button @click=»changeScore(3)»>Change Score</button>

Если мы хотим, чтобы changeScore() использовал действие вместо мутации, мы используем mapActions() следующим образом:

1
2
3
methods: {
  …Vuex.mapActions({changeScore: ‘incrementScore’})
}

Опять же, мы должны определить задержку в обработчике событий:

1
<button @click=»changeScore(3000)»>Change Score</button>

Примечание. Все помощники по отображению возвращают объект. Итак, если мы хотим использовать их в сочетании с другими локальными вычисляемыми свойствами или методами, нам нужно объединить их в один объект. К счастью, с помощью оператора распространения объекта ( ... ) мы можем сделать это без использования какой-либо утилиты.

В нашем CodePen вы можете увидеть пример того, как все помощники картирования используются на практике .

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

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

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

Давайте посмотрим на это в действии:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const childB = {
  state: {
    result: 3
  },
  getters: {
    result (state) {
      return state.result
    }
  },
  mutations: {
    increase (state, step) {
      state.result += step
    }
  },
  actions: {
    increaseResult: ({ commit }, delay) => {
      setTimeout(() => {
        commit(‘increase’, 6)
      }, delay)
    }
  }
}
 
const childA = {
  state: {
    score: 0
  },
  getters: {
    score (state) {
      return state.score
    }
  },
  mutations: {
    increment (state, step) {
      state.score += step
    }
  },
  actions: {
    incrementScore: ({ commit }, delay) => {
      setTimeout(() => {
        commit(‘increment’, 3)
      }, delay)
    }
  }
}
 
const store = new Vuex.Store({
  modules: {
    scoreBoard: childA,
    resultBoard: childB
  }
})

В приведенном выше примере мы создали два модуля, по одному для каждого дочернего компонента. Модули — это просто простые объекты, которые мы регистрируем как scoreBoard и resultBoard в объекте modules внутри магазина. Код для childA такой же, как и в магазине из предыдущих примеров. В коде childB мы добавляем некоторые изменения в значения и имена.

Давайте теперь ChildB компонент ChildB чтобы отразить изменения в модуле resultBoard .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
Vue.component(‘ChildB’,{
  template:`
    <div class=»child childB»>
      <h1> Result: {{ result }} </h1>
      <button @click=»changeResult()»>Change Result</button>
    </div>`,
  computed: {
    result () {
      return this.$store.getters.result
    }
  },
  methods: {
    changeResult () {
      this.$store.dispatch(‘increaseResult’, 3000);
    }
  }
})

В компоненте ChildA единственное, что нам нужно изменить, — это changeScore() :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
Vue.component(‘ChildA’,{
  template:`
    <div class=»child childA»>
      <h1> Score: {{ score }} </h1>
      <button @click=»changeScore()»>Change Score</button>
    </div>`,
  computed: {
    score () {
      return this.$store.getters.score
    }
  },
  methods: {
    changeScore () {
      this.$store.dispatch(‘incrementScore’, 3000);
    }
  }
})

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

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

Чтобы пространство имен модуля Vuex, вы просто устанавливаете свойство namespaced в true .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const childB = {
  namespaced: true,
  state: {
    score: 3
  },
  getters: {
    score (state) {
      return state.score
    }
  },
  mutations: {
    increment (state, step) {
      state.score += step
    }
  },
  actions: {
    incrementScore: ({ commit }, delay) => {
      setTimeout(() => {
        commit(‘increment’, 6)
      }, delay)
    }
  }
}
 
const childA = {
  namespaced: true,
  state: {
    score: 0
  },
  getters: {
    score (state) {
      return state.score
    }
  },
  mutations: {
    increment (state, step) {
      state.score += step
    }
  },
  actions: {
    incrementScore: ({ commit }, delay) => {
      setTimeout(() => {
        commit(‘increment’, 3)
      }, delay)
    }
  }
}

В приведенном выше примере мы сделали имена свойств и методов одинаковыми для двух модулей. И теперь мы можем использовать свойство или метод с префиксом имени модуля. Например, если мы хотим использовать метод получения resultBoard score() из модуля resultBoard , мы resultBoard его так: resultBoard/score . Если мы хотим получить метод scoreBoard score() из модуля scoreBoard , мы scoreBoard/score его так: scoreBoard/score .

Давайте теперь изменим наши компоненты, чтобы отразить сделанные нами изменения.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Vue.component(‘ChildB’,{
  template:`
    <div class=»child childB»>
      <h1> Result: {{ result }} </h1>
      <button @click=»changeResult()»>Change Result</button>
    </div>`,
  computed: {
    result () {
      return this.$store.getters[‘resultBoard/score’]
    }
  },
  methods: {
    changeResult () {
      this.$store.dispatch(‘resultBoard/incrementScore’, 3000);
    }
  }
})
 
Vue.component(‘ChildA’,{
  template:`
    <div class=»child childA»>
      <h1> Score: {{ score }} </h1>
      <button @click=»changeScore()»>Change Score</button>
    </div>`,
  computed: {
    score () {
      return this.$store.getters[‘scoreBoard/score’]
    }
  },
  methods: {
    changeScore () {
      this.$store.dispatch(‘scoreBoard/incrementScore’, 3000);
    }
  }
})

Как вы можете видеть в нашем примере CodePen , теперь мы можем использовать нужный метод или свойство и получить ожидаемый результат.

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

Поэтому следующим логическим шагом является разделение хранилища Vuex на отдельные файлы. Идея состоит в том, чтобы иметь отдельный файл для самого магазина и один для каждого из его объектов, включая модули. Это означает наличие отдельных файлов для состояния, геттеров, мутаций, действий и для каждого отдельного модуля ( store.js , state.js , getters.js и т. Д.). Пример этой структуры можно увидеть в конце следующего раздел.

Мы сделали магазин Vuex максимально модульным. Следующее, что мы можем сделать, это применить ту же стратегию и к компонентам Vue.js. Мы можем поместить каждый компонент в отдельный автономный файл с расширением .vue . Чтобы узнать, как это работает, вы можете посетить страницу документации Vue Single File Components .

Итак, в нашем случае у нас будет три файла: Parent.vue , ChildA.vue и ChildB.vue .

Наконец, если мы объединим все три метода, мы получим следующую или похожую структуру:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
├── index.html
└── src
    ├── main.js
    ├── App.vue
    ├── components
    │ ├── Parent.vue
    │ ├── ChildA.vue
    │ ├── ChildB.vue
    └── store
        ├── store.js
        ├── state.js
        ├── getters.js
        ├── mutations.js
        ├── actions.js
        └── modules
            ├── childA.js
            └── childB.js

В нашем уроке репозитория GitHub вы можете увидеть завершенный проект с вышеуказанной структурой.

Давайте вспомним некоторые основные моменты, которые вы должны помнить о Vuex:

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

Хранилище Vuex является реактивным, и компоненты не могут напрямую изменять его состояние. Единственный способ изменить состояние — это зафиксировать мутации, которые являются синхронными транзакциями. Каждая мутация должна выполнять только одно действие, должна быть максимально простой и отвечать только за обновление части состояния.

Асинхронная логика должна быть заключена в действиях. Каждое действие может совершить одну или несколько мутаций, и одна мутация может быть зафиксирована более чем одним действием. Действия могут быть сложными, но они никогда не меняют состояние напрямую.

Наконец, модульность является ключом к ремонтопригодности. Чтобы справиться со сложностью и сделать наш код модульным, мы используем принцип «разделяй и властвуй» и технику разделения кода.

Это оно! Вы уже знаете основные концепции Vuex и готовы начать применять их на практике.

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