En esta entrada vamos a ver cómo ahorrar cientos de líneas de código definiendo Computed Properties dinámicas con Vuejs y Vuex.
Ya sabemos que cuando trabajamos con Vuejs y Vuex haciendo uso de v-model y computed properties debemos establecer un getter y un setter para cada propiedad, el problema de esto es que si tenemos 10 computed properties podemos tener fácilmente 40 líneas de código, algo bastante difícil de mantener.
<template>
<div>
<input name="name" v-model="name" />
<input name="surname" v-model="surname" />
<input name="email" v-model="email" />
<input name="age" v-model="age" />
<input name="address" v-model="address" />
</div>
</template>
<script>
export default {
computed: {
name: {
get () {
return this.$store.state.name
},
set (val) {
this.$store.commit('setName', val)
}
},
surname: {
get () {
return this.$store.state.surname
},
set (val) {
this.$store.commit('setSurname', val)
}
},
email: {
get () {
return this.$store.state.email
},
set (val) {
this.$store.commit('setEmail', val)
}
},
age: {
get () {
return this.$store.state.age
},
set (val) {
this.$store.commit('setAge', val)
}
},
address: {
get () {
return this.$store.state.address
},
set (val) {
this.$store.commit('setAddress', val)
}
}
}
}
</script>Cómo he comentado, es fácil ver que esto es bastante complejo de mantener, así que vamos a ver de qué forma podemos mejorar ese código aplicando una sencilla lógica que sea capaz de generar todos los getters y setters de forma dinámica. Lo primero que necesitamos es el código que nos ayudará a generar estas computed properties de forma dinámica. La función que sigue hace todo lo que necesitamos:
import store from './store';
export function computedPropertiesGenerator (props = [], {pathStore, mutation} = {}) {
return props.reduce((obj, prop) => {
obj[prop.property] = {
get() {
return store.state[pathStore][prop.property] || prop.defaultValue;
},
set(value) {
store.commit(mutation, {
property: prop.property,
value
})
}
}
return obj
}, {})
}
La idea es utilizar la función reduce de JavaScript iniciando dicha función con un objeto vacío (lo puedes ver al final de la definición ({})).
De esa forma generamos un objeto con toda la información necesaria, getter y setter listos para utilizar en un componente Vuejs en forma de computed property.
Utilizando el generador en nuestros componentes
<template>
<div>
<input name="name" v-model="name" />
<input name="surname" v-model="surname" />
<input name="email" v-model="email" />
<input name="age" v-model="age" />
<input name="address" v-model="address" />
</div>
</template>
<script>
import {computedPropertiesGenerator} from "../computedPropertiesGenerator";
export default {
computed: {
...computedPropertiesGenerator([
{property: 'name', defaultValue: ''},
{property: 'surname', defaultValue: ''},
{property: 'email', defaultValue: ''},
{property: 'age', defaultValue: 18},
{property: 'address', defaultValue: null},
], {pathStore: 'user', mutation: 'setPropertyOnUser'}),
}
}
</script>Ya podemos ver cuál es la idea de utilizar un generador de código, hacer fácil algo muy tedioso, que es el databinding de Vuex a través de v-model.
Finalmente sólo necesitamos algo parecido al siguiente almacén de Vuex para manejar la lógica anterior:
export default {
state: {
user: {
name: '',
surname: '',
email: '',
age: '',
address: ''
}
},
mutations: {
setPropertyOnUser (state, data) {
state.user[data.property] = data.value;
}
}
}Así de fácil es manejar computed properties dinámicas con Vuejs y Vuex, espero que te haya gustado y que lo utilices en tus futuros proyectos.