forum
forum copied to clipboard
Criando uma Store mais simples com Vue.observable/Vue.defineReactive
Abri essa thread no twitter falando sobre como usar um state management mais simples no Vue.js em casos de projetos mais simples, usando o Vue.observable
(Vue +2.6.6) ou o Vue.defineReactive
em situações de versão inferior ao Vue 2.6
A implementação fica assim:
store.js
function createStore({ state, mutations }) {
return {
state: Vue.observable(state),
commit(key, ...args) {
mutations[key](state, ...args)
}
}
}
const store = createStore({
state: { list: [] },
mutations: {
populateList (state) {
state.list = ['Igor', 'Halfeld']
}
}
})
component.vue
<template>
<ul>
<li v-for="(item, index) in list" :key="index">{{ item }}</li>
<ul>
</template>
<script>
import Store from './store'
export default {
data: () => ({
list: Store.state.list,
})
mounted() {
Store.commit('populateList')
}
}
</script>
Muita gente se perguntou o por quê de usar dessa forma, pois parece que estou reinventando a roda, na real estou sim, mas nesse caso é pra ter toda praticidade de ter um state management e ter também um bundle menor, já que eu não preciso de features do Vuex como o watch
, subscribeMutation
, subscribeAction
, etc.. em projetos simples.
Versão com TS e Vue 3
src/store/index.ts
/* eslint-disable @typescript-eslint/no-explicit-any */
import { reactive } from 'vue'
type StoreMutation<StoreState> = (state: StoreState, ...args: any[]) => void
type StoreMutations<StoreState> = Record<string, StoreMutation<StoreState>>
type Store<StoreState> = {
state: StoreState
commit (mutation: string, ...args: any[]): void
}
/**
* Helper to create dynamic stores
* Useful to reduce boilerplate.. simple and functional
* Besides the store is standalone and works fine in a lot of places
* @param {StoreState} states
* @param {Record<string, StoreMutation<StoreState>>} mutations
*/
export function createStore<StoreState extends object> (states: StoreState, mutations: StoreMutations<StoreState>): Store<StoreState> {
return {
state: reactive<StoreState>(states) as StoreState,
commit (mutation: string, ...args: any[]) {
const handler = mutations[mutation]
if (!handler) {
return
}
handler(states, ...args)
}
}
}
Exemplo de store
src/app/store/shopping-cart/index.ts
import { createStore } from 'src/store'
import { Product } from 'src/app/definitions'
type ShoppingCart = {
products: Product[]
}
const states: ShoppingCart = {
products: []
}
const mutations = {
setProducts: (state: ShoppingCart, products: Product[]): void => {
state.products = products
}
}
const store = createStore<ShoppingCart>(states, mutations)
export default store
src/views/ShoppingCart.vue
<template>
<ul>
<li v-for="(item, index) in list" :key="index">{{ item }}</li>
<ul>
</template>
<script>
import store from 'src/app/store/shopping-cart'
export default {
setup () (
return { list: store.state.products }
),
mounted() {
store.commit('setProducts', ['Nice'])
}
}
</script>