Самоучитель №5 от JL

Серия [Истории самообучения JL]

[Net Ninja] JS Regular Expressions
[Net Ninja] Vue JS2 (Part1, Part2, Part3)
[Net Ninja] Vuex(current)
[Net Ninja] Python3 (Part1, Part2, Part3)
[Net Ninja] Django (Part1, Part2, Part3)
[Net Ninja] Sass (Part1, Part2)
[Sean Larkin] Webpack4 (Part1, Part2, Part3, Part4)

🌲 Это мое резюме Учебника Vuex от Net Ninja на YouTube.

1) What is Vuex?
2) Simple Vue App - Vanlia VueJS
3) Setting up a Central Store
4) Using Computed Properties
5) Getters
6) Mutations
7) Actions
8) Mapping Actions & Getters

1) Что такое Vuex? ("YouTube")

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

Когда нам следует использовать Vuex?

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

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

Но если вы создаете SPA среднего и крупного масштаба, скорее всего, вы столкнулись с ситуациями, которые заставят вас задуматься о том, как лучше обрабатывать состояние за пределами ваших Vue компонентов, и Vuex будет естественным следующим шагом для вас ( "Официальный веб-сайт").

Предположим, у нас есть приложение со списком дел.

Если мы создадим приложение со списком дел, используя только Vue.js, дочерним компонентам будет сложно взаимодействовать друг с другом. (В данном случае это будут «последние задачи» и «добавить задачу»).

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

Vue CLI - стандартный набор Vue.js разработки (официальный сайт). Это позволяет нам создавать рабочий процесс среды разработки с webpack. Преимущества использования webpack следующие:

  • Используйте функции ES6
  • Скомпилируйте и минимизируйте наш JS в один файл
  • Используйте однофайловые шаблоны
  • Скомпилируйте все на нашей машине, а не в браузере
  • Запустить live reload dev server

В видео использовалось Vue CLI2. Однако, поскольку видео было выпущено 30 апреля 2017 г., вышло Vue CLI3. Так что вместо этого я использовал Vue CLI3.

Если у вас есть предыдущий пакет vue-cli (1.x или 2.x), установленный глобально, вам необходимо сначала удалить его с помощью npm uninstall vue-cli -g.

  1. Используется npm install -g @vue/cli вместо npm install -g vue-cli.
  2. vue init webpack-simple <project-name>: установить webpack-simple шаблон
  3. Для начала необходимо ввести следующее по порядку: cd <project-name>, npm install (установить все зависимости, необходимые для webpack-simple) и npm run dev (запустить сервер разработки).

2) Простое приложение Vue - Vanlia VueJS (YouTube)

В этой главе было создано простое Vue приложение с использованием только Vue.js.

  • Общие данные вводятся в файл App.vue.
  • Общие данные передаются в файлы ProductListOne.vue и ProductListOne.vue через props.

[src > App.vue]
<template>
  <div id="app">
    <product-list-one v-bind:products='products'></product-list-one>
    <product-list-two v-bind:products='products'></product-list-two>
  </div>
</template>

<script>
import ProductListOne from './components/ProductListOne.vue';
import ProductListTwo from './components/ProductListTwo.vue';

export default {
  components: {
    'product-list-one': ProductListOne,
    'product-list-two': ProductListTwo,		
  },
  name: 'app',
  data () {
    return {
      products: [
        {name: 'Banana Skin', price: 20},
        {name: 'Shiny Star', price: 40},
        {name: 'Green Shells', price: 60},
        {name: 'Red Shells', price: 80}
      ]
    }
  }
}
</script>

<style>
body{
  font-family: Ubuntu;
  color: #555;
}
</style>
-----------------------------------
[src > components > ProductListOne.vue]
<template>
  <div id='product-list-one'>
    <h2>Product List One</h2>
    <ul>
      <li v-for="product in products" v-bind:key="product.id">
        <span class='name'>{{ product.name }}</span>
        <span class='price'>${{ product.price }}</span>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  props: ['products']
}
</script>

<style scoped>
#product-list-one{
  background: #FFF8B1;
  box-shadow: 1px 2px 3px rgba(0,0,0,0.2);
  margin-bottom: 30px;
  padding: 10px 20px;
}
#product-list-one ul{
  padding: 0;
}
#product-list-one li{
  display: inline-block;
  margin-right: 10px;
  margin-top: 10px;
  padding: 20px;
  background: rgba(255,255,255,0.7);
}
.price{
  font-weight: bold;
  color: #E8800C;
}
</style>
-----------------------------------
[src > components > ProductListTwo.vue]
<template>
  <div id="product-list-two">
    <h2>Product List Two</h2>
      <!-- same as ProductListOne.vue -->
  </div>
</template>

<script>
// same as ProductListOne.vue
</script>

<style scoped>
#product-list-two{
  background: #D1E4FF;
  box-shadow: 1px 2px 3px rgba(0,0,0,0.2);
  margin-bottom: 30px;
  padding: 10px 20px;
}
#product-list-two ul{
    padding: 0;
    list-style-type: none;
}
#product-list-two li{
    margin-right: 10px;
    margin-top: 10px;
    padding: 20px;
    background: rgba(255,255,255,0.7);
}
.price{
    font-weight: bold;
    color: #860CE8;
    display: block;
}
</style>

Полный код доступен для просмотра с подсветкой синтаксиса на сайте GitHubGist.

<li v-for=product in products"> работает на сервере разработки. Но в текстовом редакторе возникает следующая ошибка:

[eslint-plugin-vue] [vue/require-v-for-key] Elements in iteration expect to have 'v-bind:key' directives.

Когда v-for написано на пользовательских компонентах, одновременно требуется v-bind:key »( GitHub ). key с v-for всегда требуется для компонентов, чтобы поддерживать внутреннее состояние компонента в поддереве (« официальный веб-сайт ).

Итак, я изменил «<li v-for=product in products">» на «<li v-for=”product in products” v-bind:key=”product.id”>».

3) Создание центрального магазина (YouTube)

Чтобы установить Vuex, введите npm install vuex --save в свой терминал для Mac OS и в командную строку для Windows.

Избавьтесь от следующего из файла App.vue:

data () {
  return {
    products: [
      {name: 'Banana Skin', price: 20},
      {name: 'Shiny Star', price: 40},
      {name: 'Green Shells', price: 60},
      {name: 'Red Shells', price: 80}
    ]
  }
}

Создайте папку «store» и сохраните файл «store.js», чтобы настроить центральное хранилище.

[src > store > store.js]
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const storeData = new Vuex.Store({
  state:{
    products: [
      {name: 'Banana Skin', price: 20},
      {name: 'Shiny Star', price: 40},
      {name: 'Green Shells', price: 60},
      {name: 'Red Shells', price: 80}
    ]
  }
});

4) Использование вычисленных свойств (YouTube)

  1. Импортируйте центральное хранилище = ›добавьте import { storeData } from ‘./store/store в файл main.js.
  2. Укажите, что мы будем использовать центральное хранилище = ›addnew Vue({ store: storeData }) в файле main.js.
  3. Больше не нужно передавать какие-либо данные в виде props = ›remove v-bind:products=’products’ from<product-list-two v-bind:products=’products’></product-list-two> в файле app.vue.
  4. Больше не нужно получать данные через prop = ›избавьтесь от props: [‘products’] в файлах ProductListOne.vue и ProductListTwo.vue.
  5. Свяжитесь с нами и получите централизованно хранимые данные = ›добавьте computed: { products() { return this.$store.state.products; }} в файлы ProductListOne.vue и ProductListTwo.vue.

Полный код доступен для просмотра с подсветкой синтаксиса на сайте GitHubGist.

5) Геттеры (YouTube)

Vuex позволяет нам определять getters в магазине. Вы можете думать о них как о вычисленных свойствах для магазинов. Как и вычисляемые свойства, результат getter кэшируется на основе его зависимостей и будет повторно оцениваться только тогда, когда некоторые из его зависимостей изменились. ("Официальный веб-сайт")

Снизьте цены вдвое и вставьте «**» перед и после названия, используя свойство getters.

  • Добавьте следующий код в файл store.js.
[src > store > store.js]
export const storeData = new Vuex.Store({
  getters:{
    saleProducts: state => {
      var saleProducts = state.products.map(product => {
        return {
          name: '**'+ product.name + '**',
          price: product.price / 2
        }
      });
      return saleProducts;
    }
  }
});
  • Измените «продукты» на «saleProducts» в <li v-for=”product in products” v-bind:key=”product.id”> в файлах ProductListOne.vue и ProductListOne.vue.
  • Кроме того, добавьте следующий код в файлы ProductListOne.vue и ProductListOne.vue.
[src > components > ProductListOne.vue & ProductListTwo.vue]
export default {
  computed:{
    saleProducts(){
      return this.$store.getters.saleProducts;
    }
  }
}

Полный код доступен для просмотра с подсветкой синтаксиса на сайте GitHubGist.

6) Мутации (YouTube)

Vue имеет специальный плагин, который может помочь ускорить вашу разработку. Он не заменяет ваши журналы - он дополняет их. Он называется Vue DevTools, и вот 3 способа его использования для ускорения разработки Vue приложений: 1) Редактировать данные компонентов в реальном времени, 2) Отладка Vuex с помощью Time Travel, 3) Отслеживайте пользовательские события вашего приложения (официальный сайт).

Vue DevTools можно добавить в Chrome: перейдите здесь , чтобы добавить его.

Добавление <button @click=”reducePrice”>Reduce Price</button> & следующего метода в файл ProductListOne.vue может изменить цену. Но изменения нельзя отследить в Vue DevTools.

[src > components > ProductListOne.vue]
methods:{
  reducePrice: function() {
    this.$store.state.products.forEach(product => {
      product.price -= 1;
    });
  }
}

Чтобы отслеживать изменения, вместо включения метода «reducePrice» из файла добавьте метод как свойство мутации в центральном хранилище (в store.js).

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

[src > store > store.js]
mutations:{
  reducePrice: state => {
    state.products.forEach(product => {
      product.price -= 1;
    });
  }
}

После этого нам нужно зафиксировать мутацию. Чтобы активировать мутацию «reducePrice» в store.js, добавьте следующий код:

[src > components > ProductListOne.vue]
methods:{
  reducePrice: function() {
    this.$store.commit('reducePrice');
  }
}

Полный код доступен для просмотра с подсветкой синтаксиса на сайте GitHubGist.

Теперь мы можем отслеживать изменения. В Vue DevTools вы можете вернуть изменение или путешествие во времени к определенному состоянию.

Кроме того, вы можете включить строгий режим, просто передав strict: true при создании Vuex хранилища: const store = new Vuex.Store({ strict: true }).

В строгом режиме всякий раз, когда состояние Vuex изменяется вне обработчиков мутаций, выдается ошибка. Это гарантирует, что все мутации состояния можно явно отслеживать с помощью инструментов отладки. ("Официальный веб-сайт").

7) Действия (YouTube)

Давайте посмотрим, как мы можем работать с асинхронными операциями. Мы проверим это с помощью функции «setTimeout».

Если мы добавим функцию как свойство «мутации» в store.js, как показано ниже, возникнет проблема. После нажатия кнопки «Снизить цену» фактические изменения происходят через три секунды, но изменения отражаются в Vue DevTools, как только кнопка нажата.

[src > store > store.js]
mutations:{
  reducePrice: state => {
    setTimeout(function(){
      state.products.forEach(product => {
        product.price -= 1;
      })
    }, 3000)
  }
}

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

Действия похожи на мутации, отличия заключаются в следующем: 1) вместо изменения состояния действия совершают мутации. 2) Действия могут содержать произвольные асинхронные операции (официальный сайт).

›Обработчики действий получают объект контекста, который предоставляет тот же набор методов / свойств в экземпляре магазина ( официальный сайт ).

[src > store > store.js]
mutations:{
  reducePrice: state => {
    state.products.forEach(product => {
      product.price -= 1;
    })
  }
},
actions:{
  reducePrice: context => {
    setTimeout(function(){
      context.commit('reducePrice')
    }, 3000)
  }
}

Также в методе reducePrice в ProductListOne.vue измените «commit» на «dispatch».

[src > components > ProductListOne.vue]
methods:{
  reducePrice: function() {
    this.$store.dispatch('reducePrice');
  }
}

Теперь изменения отражаются в Vue DevTools через три секунды после нажатия кнопки «Снизить цену».

Что, если мы хотим передать параметр, который снижает цену на определенную величину? Это может быть динамическое (например, пользователь может ввести сумму). Но в этом руководстве мы просто передаем число.

Вы можете передать дополнительный аргумент, который называется полезной нагрузкой для мутации (официальный сайт).

[src > store > store.js]
mutations:{
  reducePrice: (state, payload) => {
    state.products.forEach(product => {
      product.price -= payload;
    })
  }
},
actions:{
  reducePrice: (context, payload) => {
    setTimeout(function(){
      context.commit('reducePrice', payload)
    }, 3000)
  }
}

Кроме того, внесите следующие изменения в ProductListOne.vue,

  • <button @click="reducePrice(4)">Reduce Price</button> в шаблоне: уменьшить на 4.
  • this.$store.dispatch('reducePrice', amount) в методах: добавить «количество»

Полный код доступен для просмотра с подсветкой синтаксиса на сайте GitHubGist.

8) Mapping Actions & Getters (YouTube)

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

export default{
  computed:{
    firstGetter(){
      return this.$store.getters.firstGetter;
    },
    secondGetter(){
      return this.$store.getters.secondGetter;
    },
    thirdGetter(){
      return this.$store.getters.thirdGetter;
    }
  },
  methods:{
    firstAction: function(amount) {
      this.$store.dispatch('firstAction', amount);    
    },
    secondAction: function(amount) {
      this.$store.dispatch('secondAction', amount);    
    },
    thirdAction: function(amount) {
      this.$store.dispatch('thirdAction', amount);    
    },
  }
}

Однако, если их много, код становится слишком длинным.

Есть способ сопоставить геттеры со свойством computed и сопоставить действия со свойством methods!

[src > components > ProductListOne.vue]
import { mapGetters } from 'vuex';
import { mapActions } from 'vuex';
export default{
  computed:{
    ...mapGetters({
      'firstGetter',
      'secondGetter',
      'thirdGetter'
    })
  },
  methods:{
    ...mapActions({
      'firstAction',
      'secondAction',
      'thirdAction'
    })
  }
}

Кстати, ... (синтаксис распространения) - это функциональность ES6. Чтобы использовать его в браузере, нам понадобится Babel.

Babel - это транспилятор JavaScript, который преобразует крайний JavaScript в простой старый JavaScript ES5, который может работать в любом браузере (даже в старых). Он делает доступным весь синтаксический сахар, который был добавлен в JavaScript с новой спецификацией ES6 (блог).

С тех пор, как Net Ninja выпустил это видео в октябре 2017 года, вышел Babel stage-3. Введите следующее в терминале для Mac OS и в командной строке для Windows (npm).

npm install --save-dev babel-preset-stage-3

Доступно для просмотра окончательного кода с подсветкой синтаксиса на сайте GitHubGist.

Спасибо за прочтение! 💕 Если вам понравился этот пост в блоге, пожалуйста, хлопайте в ладоши👏