Использование Vue.Observable в качестве State Store
Хотите легкую альтернативу Vuex для управления состоянием в веб-приложениях Vue.js?
Vue.Observable может использоваться как хранилище состояний state store вместо Vuex в простых приложениях.
В версии 2.6.0 Vue.js добавлен Vue.Observable. Эта функция, делает переданный ей объект реактивным. В Vue объекты не становятся реактивными автоматически. Это означает, что если мы хотим реагировать на изменение свойств объекта, нам нужно проделать дополнительную работу. Vue.Observable делает это супер легко. Подробнее о реактивности во Vue читайте здесь.
Non-Reactivity
const obj = {x: 0, y: 0}; export default { // Vue component data() { return {}; }, method() { updateObj() { obj.x = 1; obj.y = 2; } } }
В этом примере вызов updateObj не приведет к повторному вычислению значений и к повторному отображению их в шаблонах. К счастью, компоненты Vue имеют функцию data. Объект, возвращаемый data, является реактивным!
Reactivity через data()
export default { // Vue component data() { return { obj: {x: 0, y: 0} }; }, method() { updateObj() { this.obj.x = 1; this.obj.y = 2; } } }
Поскольку данные в data реактивные, вызов updateObj приведет к пересчету вычисленных значений, которые зависят от obj, и они обновится в шаблонах при необходимости.
Breakout State из Components
В обычных компонентах/приложениях все изменяемые данные помещаются в объект, возвращаемый функцией data. Но хранение всех данных приложения в функциях data в каждом компоненте не вариант. В частности, это становится проблемой, когда данные должны передаваться между одноуровневыми компонентами.
Передает ли компонент с данными его родительскому компоненту через события, а затем родительский компонент передает его дочернему компоненту через props? Даже в простых случаях это становится большой головной болью. Все эти данные сильно связывают компоненты, их становиться сложно тестировать, они становятся больше подвержены ошибкам и вся эта ситуация просто сбивает с толку.
Тут нам может помочь единое хранилище state stores.
State Management
Vuex — подключаемый модуль хранилища состояний для Vue.js. Вот как vuejs.org описывает Vuex:
Vuex — это шаблон управления состоянием + библиотека для приложений Vue.js. Он служит централизованным хранилищем для всех компонентов приложения с правилами, гарантирующими, что состояние может быть изменено только предсказуемым образом.
Это здорово, но Vuex не совсем тривиален в использовании. Во-первых, его нужно добавить как плагин к вашему приложению Vue. Во-вторых, это очень мощный инструмент, с которым сложно разобраться новичкам. Наконец, многие приложения достаточно просты, чтобы не нуждаться в Vuex и всех его функциях для управления состоянием.
Итак, какова альтернатива Vuex? Конечно, ответом является тема этого поста: Vue.Observable.
Vue.Observable как State Store
Рассмотрим пример использования Vue.Observable в качестве хранилища состояний.
store.js
import Vue from 'vue'; import axios from 'axios'; const state = Vue.Observable({ // this is the magic radius: 0, color: 'red' }); export const getters { radius: () => state.radius, color: () => state.color } export const mutations { setRadius: (val) => state.radius = val, setColor: (val) => state.color = val } export const actions { fetchRadiusFromApi() { return axios .get('http://localhost:5001/api/radius') .then((res) => { mutations.setRadius(res.data); }); }, fetchColorFromApi() { return axios .get('http://localhost:5001/api/color') .then((res) => { mutations.setColor(res.data); }); } }
В строке 4, где мы объявляем состояние state, происходит важная часть. Геттеры (getters) и мутации (mutations) — это то, как мы получаем и обновляем состояние. К действиям (actions) относятся асинхронные вызовы, а именно запросы API. Действия совершают мутации, потенциально основанные на результатах запросов API.
И пример использования описанного выше хранилища в компоненте.
component.vue
<template> <div> <div>Radius: {{ radius }}</div> <div>Color: {{ color }}</div> <button @:click="setRadius(0)">Reset radius</button> <button @:click="fetchColorFromApi">Fetch color</button> </div> </template> <script> import { getters, mutations, actions } from 'store.js'; export default { data() { return {}; }, computed() { ...getters // radius(), color() }, created() { this.fetchRadiusFromApi(); // fetching data right away this.fetchColorFromApi().then(() => { console.log('You can chain then after actions, if you return the request'); }); } methods() { ...mutations, // setRadius(val), setColor(val) ...actions // fetchRadiusFromApi(), fetchColorFromApi() } } </script>
Заключение
Любые компоненты могут просто импортировать store.js и использовать одно и то же состояние. Нет необходимости использовать props/events для передачи данных.
Бонусный совет для компонентов, которым не нужны геттеры, а нужны вычисляемые значения computed:
component.js
computed() { // ...getters <- instead of this, do this: radius() { return getters.radius; }, diameter() { return getters.radius * 2; } // this component doesn't need color }
Оригинальная статья Austin Cooper — Using Vue Observable as a State Store