Saltar al contenido

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.

Rutas de aprendizaje