giraud florent

Vue 2.6.6 Release part3 Vue.observable

Create custom Store without vuex Vue.observable

Good morning, everyone. In the continuation of my articles on the release 2.6.6 of vuejs, we will talk today about the observable.Vue.

First of all and for the comprehension of all. the observable in Vuejs are not Proxy for the moment.

According to the doc

In Vue 2.x, Vue.observable directly mutates the object passed to it, so that it is equivalent to the object returned, as demonstrated here. In Vue 3.x, a reactive proxy will be returned instead, leaving the original object non-reactive if mutated directly. Therefore, for future compatibility, we recommend always working with the object returned by Vue.observable, rather than the object originally passed to it.

So they will only be integrated with version 3 of vuejs and will allow more freedom to add trappers on them.

Let me show you a simple example of how to create a custom store with observable.

At any time you can see the final code ICI

Our template:

// App.vue
<template>
  <div id="app">
    <h1>
      {{count}}
    </h1>
    <button @click="updateCount">Click</button>
  </div>
</template>

<script>
export default {
  name: "pickles",
  computed: {
    count: {
      get() {
        return this.$store.user.getters.getCount();
      }
    }
  },
  methods: {
    updateCount() {
      this.$store.viewer.mutations.updateCount();
    }
  }
};
</script>

Our store:

// store.js
import Vue from 'vue';

import User from "./store/user"
import Viewer from "./store/viewer";

class Store {
    constructor(obj) {
      this.hydrateStore(obj)
    }

    hydrateStore(obj) {
        for (let k in obj) {
            this[k] = {
                state: Vue.observable(obj[k].state || {}),
                getters: obj[k].getters || {},
                mutations:obj[k].mutations || {},
                actions: obj[k].actions || {}
            };
        }
    }
}

const customStore =  new Store({
    user: User,
    viewer: Viewer
})

Vue.prototype.$store = customStore;

export default customStore;

As you can see we are creating a class that will create our Store by adding the observable ones to our different states in order to make them reactive with Vuejs. Then we integrate them into the view instance thanks to Vue.prototype which will make our Store accessible in all your Components.

Our stores:

// store/user.js
import Vue from 'vue';

export const state = {
    count: 0
}

export const getters = {
    getCount() {
        return state.count;
    }
};

export const mutations = {
    updateCount() {
        state.count += 1;
    }
}

export const actions = {}

export default {
    state,
    getters,
    mutations,
    actions
}

// store/viewer.js
import Vue from 'vue';

import User from "./user";

export const state = {}

export const getters = {}

export const mutations = {
    updateCount() {
        User.mutations.updateCount()
        actions.sayHello()
    }
}

export const actions = {
    sayHello() {
        console.log("hello")
    }
}

export default {
    state,
    getters,
    mutations,
    actions
}

In updateCount we call another mutation from another "nameSpace" that will change its state and still remain reactive.

However, you do not have access to commit("mutationNAme", null, {root: true}) or dispatch etc...

Nevertheless you have a functional Store that will meet most of your needs without having to increase the size of your bundle with Vuex.