Поиск…


Вступление

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

Что такое Vuex?

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

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

Пример потока данных в приложении Vuex описан на диаграмме ниже. Архитектура приложения Vuex Диаграмма, используемая в соответствии с лицензией MIT , первоначально из официального репо Vuex GitHub .

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

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

Изменения автоматически отражаются во всем приложении, так как все компоненты реагируют на хранилище через свои геттеры.


Пример , иллюстрирующий использование vuex в проекте вю.

const state = {
    lastClickTime: null
}

const mutations = {
    updateLastClickTime: (state, payload) => {
      state.lastClickTime = payload
  }
}

const getters = {
  getLastClickTime: state => {
    return new Date(state.lastClickTime)
  }
}

const actions = {
    syncUpdateTime: ({ commit }, payload) => {
    commit("updateLastClickTime", payload)
  },
  asyncUpdateTime: ({ commit }, payload) => {
    setTimeout(() => {
      commit("updateLastClickTime", payload)
    }, Math.random() * 5000)
  }
}

const store = new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})

const { mapActions, mapGetters } = Vuex;

// Vue 
const vm = new Vue({
    el: '#container',
  store,
  computed: {
      ...mapGetters([
        'getLastClickTime'
    ])
  },
  methods: {
      ...mapActions([
        'syncUpdateTime',
      'asyncUpdateTime'
    ]),
    updateTimeSyncTest () {
        this.syncUpdateTime(Date.now())
    },
    updateTimeAsyncTest () {
        this.asyncUpdateTime(Date.now())
    }
  }
})

И HTML-шаблон для этого же:

<div id="container">
  <p>{{ getLastClickTime || "No time selected yet" }}</p>
  <button @click="updateTimeSyncTest">Sync Action test</button>
  <button @click="updateTimeAsyncTest">Async Action test</button>
</div>
  1. Здесь состояние содержит свойство lastClickTime, инициализированное как null. Эта настройка значений по умолчанию важна для сохранения реактивности . Свойства, не упомянутые в состоянии, будут доступны, но изменения, сделанные после этого , не будут доступны с помощью геттеров.

  2. Используемый getter предоставляет вычисленное свойство, которое будет обновляться каждый раз, когда мутация обновляет значение свойства state.

  3. Только мутациям разрешено изменять состояние и его свойства, при этом он делает это только синхронно .

  4. Действие может быть использовано в случае асинхронных обновлений, в которых вызов API (здесь издевается случайно заданный setTimeout) может быть сделан в действии, и после получения ответа мутация может быть зафиксирована, чтобы внести изменения в состояние ,

Зачем использовать Vuex?

При создании больших приложений, таких как Single Pages Apps (SPA), которые обычно состоят из многих компонентов многократного использования, они могут быстро стать сложными для создания и поддержки. Обмен данными и состоянием между этими компонентами также может быстро разрушаться и становится трудно отлаживать и поддерживать.

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

Компоненты VueJS являются отдельными объектами, и они не могут легко обмениваться данными между собой. Для того, чтобы обмениваться данными без vuex мы должны emit событие с данными , а затем слушать и поймать это событие с on .

компонент 1

this.$emit('eventWithDataObject', dataObject)

компонент 2

this.$on('eventWithDataObject', function (dataObject) {
    console.log(dataObject)
})

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

this.$store.state.myData

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

Функции Getter могут работать как глобальные вычислительные функции. Мы можем получить к ним доступ из компонентов:

this.$store.getters.myGetter

Действия - это глобальные методы. Мы можем отправить их из компонентов:

this.$store.dispatch('myAction', myDataObject)

И мутации - единственный способ изменить данные в vuex. Мы можем зафиксировать изменения:

this.$store.commit('myMutation', myDataObject)

Код Vuex будет выглядеть следующим образом:

state: {
  myData: {
    key: 'val'
  }
},
getters: {
  myGetter: state => {
     return state.myData.key.length
  }
},
actions: {
  myAction ({ commit }, myDataObject) {
    setTimeout(() => {
      commit('myMutation', myDataObject)
    }, 2000)
  }
},
mutations: {
  myMutation (state, myDataObject) {
    state.myData = myDataObject
  }
}

Как установить Vuex?

Большую часть времени, когда вы будете использовать Vuex, будут в приложениях с большими компонентами, где вы, вероятно, будете использовать набор модулей, например Webpack или Browserify, вместе с Vueify, если вы используете отдельные файлы.

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

 npm install --save vuex

Убедитесь, что вы загружаете ссылку Vuex с настройкой Vue, поместив следующую строку после инструкции require('vue') .

Vue.use(require('vuex'))

Vuex также доступен на CDN; вы можете взять последнюю версию cdnjs здесь .

Автоотложные уведомления

Этот пример будет динамически регистрировать vuex-модуль для хранения пользовательских уведомлений, которые могут автоматически отклоняться

notifications.js

разрешить хранилище vuex и определить некоторые константы

//Vuex store previously configured on other side
import _store from 'path/to/store';

//Notification default duration in milliseconds
const defaultDuration = 8000;

//Valid mutation names
const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED';
const NOTIFICATION_DISMISSED = 'NOTIFICATION_DISMISSED';

установить начальное состояние модуля

const state = {
  Notifications: []
}

установить наши модули

const getters = {
  //All notifications, we are returning only the raw notification objects
  Notifications: state => state.Notifications.map(n => n.Raw)
}

установить наш модуль

const actions = {
  //On actions we receive a context object which exposes the 
  //same set of methods/properties on the store instance
  //{commit} is a shorthand for context.commit, this is an 
  //ES2015 feature called argument destructuring
  Add({ commit }, notification) {
    //Get notification duration or use default duration
    let duration = notification.duration || defaultDuration

    //Create a timeout to dismiss notification
    var timeOut = setTimeout(function () {
      //On timeout mutate state to dismiss notification
      commit(NOTIFICATION_DISMISSED, notification);
    }, duration);

    //Mutate state to add new notification, we create a new object 
    //for save original raw notification object and timeout reference
    commit(NOTIFICATION_ADDED, {
      Raw: notification,
      TimeOut: timeOut
    })
  },
  //Here we are using context object directly
  Dismiss(context, notification) {
    //Just pass payload
    context.commit(NOTIFICATION_DISMISSED, notification);
  }
}

установить наши мутации модуля

const mutations = {
  //On mutations we receive current state and a payload
  [NOTIFICATION_ADDED](state, notification) {
    state.Notifications.push(notification);
  },
  //remember, current state and payload
  [NOTIFICATION_DISMISSED](state, rawNotification) {
    var i = state.Notifications.map(n => n.Raw).indexOf(rawNotification);
    if (i == -1) {
      return;
    }

    clearTimeout(state.Notifications[i].TimeOut);
    state.Notifications.splice(i, 1);
  }
}

Зарегистрируйте наш модуль с определенным состоянием, геттерами, действиями и мутацией

_store.registerModule('notifications', {
  state,
  getters,
  actions,
  mutations
});

использование

componentA.vue

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

<template>
<transition-group name="notification-list" tag="div" class="top-right">
  <div v-for="alert in alerts" v-bind:key="alert" class="notification alert alert-dismissible" v-bind:class="'alert-'+alert.type">
    <button v-on:click="dismiss(alert)" type="button" class="close" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    <div>
      <div>
        <strong>{{alert.title}}</strong>
      </div>
      <div>
        {{alert.text}}
      </div>
    </div>
  </div>
</transition-group>
</template>

<script>
export default {
  name: 'arc-notifications',
  computed: {
    alerts() {
      //Get all notifications from store
      return this.$store.getters.Notifications;
    }
  },
  methods: {
    //Manually dismiss a notification
    dismiss(alert) {
      this.$store.dispatch('Dismiss', alert);
    }
  }
}
</script>
<style lang="scss" scoped>
$margin: 15px;

.top-right {
    top: $margin;
    right: $margin;
    left: auto;
    width: 300px;
    //height: 600px;
    position: absolute;
    opacity: 0.95;
    z-index: 100;
    display: flex;
    flex-wrap: wrap;
    //background-color: red;
}
.notification {
    transition: all 0.8s;
    display: flex;
    width: 100%;
    position: relative;
    margin-bottom: 10px;
    .close {
        position: absolute;
        right: 10px;
        top: 5px;
    }

    > div {
        position: relative;
        display: inline;
    }
}
.notification:last-child {
    margin-bottom: 0;
}
.notification-list-enter,
.notification-list-leave-active {
    opacity: 0;
    transform: translateX(-90px);
}
.notification-list-leave-active {
    position: absolute;
}
</style>

Фрагмент для добавления уведомлений в любой другой компонент

//payload could be anything, this example content matches with componentA.vue 
this.$store.dispatch('Add', {
  title = 'Hello',
  text = 'World',
  type = 'info',
  duration = 15000
});


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow