Vuex state and getters

enguerran

enguerran 🐐💨

Posted on March 10, 2020

Vuex state and getters

(edit) I have evolved my thinking on the subject, which I have expressed in a new article: https://dev.to/enguerran/vuex-state-and-getters-2-2l34

With vuex is there a reason why it's better to access state directly than via a getter if the getter is just returning the state?

Vuex state and getters

Let us first take care to illustrate this issue:

the store

const store = new Vuex.Store({
  state: {
    messages: [
      { from: "Bob", to: "Alice", content: "Hello, Alice!" },
      { from: "Alice", to: "Bob", content: "Hi, Bob!" },
      {
        from: "Bob",
        to: "Alice",
        content:
          `What is the difference between accessing the state directly
          rathen than using a getter?`
      },
      {
        from: "Alice",
        to: "Bob",
        content: `This is your last chance.
          After this, there is no turning back.
          You take the blue pill—the story ends,
          you wake up in your bed and believe whatever you want to believe.
          You take the red pill—you stay in Wonderland,
          and I show you how deep the rabbit hole goes.
          Remember: all I'm offering is the truth. Nothing more.`
      }
    ]
  },
  getters: {
    messages: state => state.messages
  }
});
Vuex store

two very different components

In both components, messages are the responsibility of a Vuex store.

RedPill: direct access to the state

export default {
  name: "HelloWorld",
  computed: {
    messages() {
      return this.$store.state.messages;
    }
  }
};
RedPill component

In the component <RedPill />, we access the state directly via the store object which is injected to all root child components.

The component retrieves the list of messages and can display their content:

<template>
  <div class="hello">
    <h1>Dependant of the state organization</h1>
    <ul v-for="(message, index) in messages" :key="index">
      <li>{{message.from}} to {{message.to}}: {{message.content}}</li>
    </ul>
  </div>
</template>
Vue template to display messages

BluePill: using a getter

export default {
  name: "HelloWorld",
  computed: {
    messages() {
      return this.$store.getters.messages;
    }
  }
};
BluePill component

In the other component <BluePill />, we access the state via a getter which is not complex since it returns directly the object: const messages = state => state.messages.

From a component and the application point of view, there is no difference.

how deep does the rabbit hole go?

The RedPill is dependant of the internal state organization. Every time the state is reorganized, the RedPill should be updated. The RedPill has a big responsibility: to know where it can find the list of messages.

On the other hand, the BluePill is independent of the internal organization of the state because it asks the store, whenever it needs it, to return the list of messages. The BluePill does not have the responsibility to know where it can find the list of messages.

Let's say that the Vuex store is redesigned to allow organization in modules.

const store = new Vuex.Store({
  state: {
    messages: [
      { from: "Bob", to: "Alice", content: "Hello, Alice!" },
      { from: "Alice", to: "Bob", content: "Hi, Bob!" },
      {
        from: "Bob",
        to: "Alice",
        content:
          `What is the difference between accessing the state directly
          rathen than using a getter?`
      },
      {
        from: "Alice",
        to: "Bob",
        content: `This is your last chance.
          After this, there is no turning back.
          You take the blue pill—the story ends,
          you wake up in your bed and believe whatever you want to believe.
          You take the red pill—you stay in Wonderland,
          and I show you how deep the rabbit hole goes.
          Remember: all I'm offering is the truth. Nothing more.`
      }
    ]
  },
  getters: {
    messages: state => state.messages
  }
});
Vuex store before refactoring

Now we want to use Vuex modules:

const store = new Vuex.Store({
  modules: {
    messages: {
      state: {
        messages: [
          { from: "Bob", to: "Alice", content: "Hello, Alice!" },
          { from: "Alice", to: "Bob", content: "Hi, Bob!" },
          {
            from: "Bob",
            to: "Alice",
            content: `What is the difference between accessing the state directly
              rathen than using a getter?`
          },
          {
            from: "Alice",
            to: "Bob",
            content: `This is your last chance.
              After this, there is no turning back.
              You take the blue pill—the story ends,
              you wake up in your bed and believe whatever you want to believe.
              You take the red pill—you stay in Wonderland,
              and I show you how deep the rabbit hole goes.
              Remember: all I'm offering is the truth. Nothing more.`
          }
        ]
      },
      getters: {
        messages: state => state.messages
      }
    }
  }
});
Vuex store with modules

I have to update the RedPill computed data:

export default {
  name: "HelloWorld",
  computed: {
    messages() {
      return this.$store.state.messages.messages;
    }
  }
};
Tightly coupled to the store

But not the BluePill's one.

export default {
  name: "HelloWorld",
  computed: {
    messages() {
      return this.$store.getters.messages;
    }
  }
};
Weakly coupled to the store

And that is the same about adding a new feature.

Let's say messages are updated to have a boolean that expresses the need to be displayed or not: draft: true.

You just need to update the getter and everything is right:

getters: {
  messages: state => state.messages.filter(message => !message.draft)
}
Shotgun surgery avoidance

That is an introduction to coupling in software development.

💖 💪 🙅 🚩
enguerran
enguerran 🐐💨

Posted on March 10, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Vuex state and getters
development Vuex state and getters

March 10, 2020