Vuex state and getters

Vuex state and getters
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?

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.

A complete codesandbox is available if you want to play with the code.