Que é Vuex Storage Plugin e por quê?
O que é?
Vuex Storage Plugin é um plugin para Vuex para persistir dados de sua store no localStorage,
sessionStorage e etc. Ele oferece a configuração convencional na criação do Vuex.Store
para o rootState
e módulos estáticos, mas também oferece configuração para módulos dinâmicos.
Por que?
Quando precisei armazenar alguns dados da minha store no
sessionStorage não encontrei nenhum plugin simples de usar, fácil de aprender e que se
encaixa-se à minha aplicação sem grandes alterações.
Precisava que o plugin armazena-se apenas alguns atributos de módulos
dinâmicos e não encontrei nada do tipo ou pelo menos a documentação não me ajudou muito.
Instalação
npm install --save vuex-storage-plugin
Nuxt
// nuxt.config.js
...
plugins: [{ src: '~/plugins/vuex-storage-plugin.config.js', ssr: false }]
...
// ~/plugins/vuex-storage-plugin.config.js
import VuexStoragePlugin from 'vuex-storage-plugin';
export default ({store}) => {
window.onNuxtReady(() => {
VuexStoragePlugin({...})(store);
});
}
Configuração
import Vue from 'vue';
import Vuex from 'vuex';
import VuexStoragePlugin from 'vuex-storage-plugin';
Vue.use(Vuex);
// rootState and static modules configuration
const vuexStoragePluginConfig = {
prefix: 'vuex',
storage: {},
removeIfNull: true,
populate: [],
afterPopulate: () => {}
};
const store = new Vuex.Store({
plugins: [new VuexStoragePlugin(vuexStoragePluginConfig)]
});
...
// dynamic modules configuration
store.registerModule('DynamicModule', {
...,
populate: [],
afterPopulate: () => {}
});
Atributo | Tipo | Descrição |
---|---|---|
prefix | String, default 'vuex' | Prefixo usado na chave do storage, exemplo: "vuex/myAttr" |
storage | Storage | API usada para persistir o estado da aplicação |
removeIfNull | Boolean, default true | Indica se o plugin deve remover o valor do storage ou salvar null |
populate | Array de String e/ou Object | Indica os módulos, atributos e mutations que devem ser persistidos |
afterPopulate | Function | Hook chamado logo após o estado root ou do módulo ser carregado na store |
storage
Seguindo a interface de Web Storage API, como localStorage ou sessionStorage.
Os métodos necessários para o plugin são os seguintes:
interface Storage {
getItem(key: string): string
setItem(key: string, value: string)
removeItem(key: string)
}
Dica
Caso queira criar seu Storage personalizado ou fazer um wrapper para uma lib como js-cookie você só precisa implementar os métodos acima, exemplo:
import Cookies from 'js-cookie';
const CookiesWrapper = {
setItem: Cookies.set,
getItem: Cookies.get,
removeItem: Cookies.remove
};
populate
O atributo populate é onde você indicará quais os atributos devem ser persistidos no storage e
populados do storage na criação do Vuex.Store
ou no registro de um módulo dinâmico.
Há duas maneiras de se configurar este atributo:
- Usando Strings que representam o nome dos atributos e das mutations usadas para atualizar seus valores
- Usando Objetos complexos
Usando Strings
Quando usando String entendesse que foi usado o mesmo nome do atributo à mutation responsável por sua atualização.
Usando estado estático:
import Vue from 'vue';
import Vuex from 'vuex';
import VuexStoragePlugin from 'vuex-storage-plugin';
Vue.use(Vuex);
const vuexStoragePluginConfig = {
storage: localStorage,
populate: ['attr']
};
const store = new Vuex.Store({
plugins: [new VuexStoragePlugin(vuexStoragePluginConfig)],
state() {
return {
attr: null
}
},
mutations: {
attr(state, value) {
state.attr = value;
}
}
});
...
store.commit('attr', 'attrs new value');
Usando módulo dinâmico:
import Vue from 'vue';
import Vuex from 'vuex';
import VuexStoragePlugin from 'vuex-storage-plugin';
Vue.use(Vuex);
const vuexStoragePluginConfig = {
storage: localStorage
};
const store = new Vuex.Store({
plugins: [new VuexStoragePlugin(vuexStoragePluginConfig)]
});
...
// unnamespaced module
store.registerModule('UnnamedModule', {
state() {
return {
attr: null
}
},
mutations: {
attr(state, value) {
state.attr = value;
}
},
populate: ['attr']
});
store.commit('attr', 'unnamed attrs new value');
// namespaced module
store.registerModule('NamedModule', {
namespaced: true,
state() {
return {
attr: null
}
},
mutations: {
attr(state, value) {
state.attr = value;
}
},
populate: ['attr']
});
store.commit('NamedModule/attr', 'named attrs new value');
Atenção
Configuração como String funciona apenas para o state raíz da store e módulos dinâmicos.
Para módulos estáticos é necessário configuração do nome do módulo junto aos nomes
do atributo e mutation.
Usando Objetos
Usando Objetos permite que você use atributos e mutations com nomes diferentes,
o nome do módulo sendo configurado e também permite que você defina um valor default
para o atributo quando o plugin não encontrar o valor do atributo no storage.
Interface do objeto esperado
interface PopulateItem {
module: string,
attr: string,
mutation: string,
default: any
}
Atributo | Descrição |
---|---|
module | Nome do módulo da configuração. Não importa se é nomeado ou não, se não for dinâmico tem de colocar o módulo |
attr | Nome do atributo que deseja persistir no storage |
mutation | Nome do mutation a ser observado para persistir na store* |
default | Valor a ser atribuído quando não existe valor no storage, o valor default é null |
storage | Um storage como na configuração global no caso de você querer usar um storage diferente para um state especifico |
Atenção
É persistido no storage o valor passado como parâmetro para a mutation. Caso o valor seja "processado" dentro da mutation, isso não é visível para o plugin.
import Vue from 'vue';
import Vuex from 'vuex';
import VuexStoragePlugin from 'vuex-storage-plugin';
Vue.use(Vuex);
const vuexStoragePluginConfig = {
populate: [{
attr: 'attr',
mutation: 'setAttr'
}]
};
const store = new Vuex.Store({
plugins: [new VuexStoragePlugin(vuexStoragePluginConfig)],
state() {
return {
attr: null
}
},
mutations: {
setAttr(state, payload) {
state.attr = `bacon is ${payload}`;
}
}
});
store.commit('setAttr', 'love');
O valor persistido será "love"
, não "bacon is love"
afterPopulate
Caso você deseje realizar alguma lógica após receber os dados do storage,
o afterPopulate
tem a proposta de ser um hook
chamado após os dados serem restaurados do storage e
inseridos no store.
Existem duas assinaturas de método para esse hook
:
- Estático raíz e módulos dinâmicos não nomeados, executado após criação da store raíz
- Módulo dinâmico e nomeado, executado ao registrar um novo módulo
function(rootStore); // static and unnamed modules
function(moduleStore, rootStore); // dynamic modules