How to Use Vuex in a Nuxt Project demo repo

Vuex (opens new window) is a state management pattern and library for Vue.js applications.

This tutorial uses Github's Markdown API (opens new window).

# 👣 Steps

  1. Create a Nuxt project.
npx create-nuxt-app nuxt-demo
cd nuxt-demo

INFO

Vuex is already included in Nuxt so there is no need to install it.

  1. Create a template, e.g. in pages/vuex.vue.
<template>
  <client-only>
    <div>
      <h1>Vuex Demo</h1>

      <b-form-textarea
        id="result"
        v-model="input"
        class="bg-dark container mb-4 text-white"
        rows="10"
        autofocus
        @input="renderPreview"
      >
      </b-form-textarea>

      <b-container
        class="border border-primary"
        v-html="renderedMd"
      ></b-container>
    </div>
  </client-only>
</template>
  1. Create a module, e.g. store/markdown.js.
export const state = () => ({
  input: `# Under the Sea

  *Source*: [Color of the year **2019**](https://www.pantone.com/color-intelligence/color-of-the-year/color-of-the-year-2019-palette-exploration)

  > Awash in color suggestive of the watery environment that lies beneath a tropical island paradise, Under The Sea places \`PANTONE\` Living Coral at the center of our naturally vivid and chromatic ecosystem, evocative of how coral reefs embrace with their warmth and nourishment and provide shelter to a diverse kaleidoscope of colorful sea life.

  ---

  * Sea pink
  * Limpet Shell
  * Living Coral
  * Vibrant Yellow 
  * Turkish Sea
  * Turtle Green
  * Blue Depths

  ![Color harmonies](/color-harmonies.png)`,
  renderedMd: ""
});

export const actions = {
  async renderPreview({ commit }, input) {
    try {
      const url = `https://api.github.com/markdown`;

      const response = await fetch(url, {
        Accept: "application/vnd.github.v3+json",
        method: "POST",
        headers: {
          "Content-Type": "text/html"
        },
        body: JSON.stringify({ text: input, mode: "gfm" })
      });

      if (response.ok) {
        const renderedMd = await response.text();

        commit("renderedMd", renderedMd);
      }
    } catch (error) {
      console.log(error); // eslint-disable-line no-console
    }
  }
};

export const mutations = {
  updateInput(state, input) {
    state.input = input;
  },
  renderedMd(state, result) {
    state.renderedMd = result;
  }
};

export const getters = {
  input: state => {
    return state.input;
  },
  renderedMd: state => {
    return state.renderedMd;
  }
};
  1. Use Vuex to complete the template, i.e. in pages/vuex.vue.
<template>
  <client-only>
    <div>
      <h1>Vuex Demo</h1>

      <b-form-textarea
        id="result"
        v-model="input"
        class="bg-dark container mb-4 text-white"
        rows="10"
        autofocus
        @input="renderPreview"
      >
      </b-form-textarea>

      <b-container
        class="border border-primary"
        v-html="renderedMd"
      ></b-container>
    </div>
  </client-only>
</template>

<script>
export default {
  computed: {
    input: {
      get() {
        return this.$store.getters["markdown/input"];
      },
      set(value) {
        this.$store.commit("markdown/updateInput", value);
      }
    },
    renderedMd() {
      return this.$store.getters["markdown/renderedMd"];
    }
  },
  mounted() {
    this.renderPreview();
  },
  methods: {
    renderPreview() {
      this.$store.dispatch("markdown/renderPreview", this.input);
    }
  }
};
</script>

# 📖 Explanation

Click if you are not familiar with Vuex yet 😕

In simple words, Vuex (opens new window) is something we can use to manage state in our Vue project. Store is the container. This store consists of 4 parts:

Our Vue component render the initial state. Then, when we want to change it, perhaps after a button click, the component calls an action with dispatch. Vuex actions contains the actions we can use.

The called action does something, for example, make an API call. That action results in something we can change the state with. So at the end of the action, we commit that result. Vuex mutations contains the changes or mutations we can make.

When the change is already committed, the mutations mutate the state. Our component can access the state using getters. Getters are like the final processor of your state, so your component can get a ready to use state.

The component can also access the state without getters. It is OK to omit the getter if there is no need to process the state.

Finally, the component will re-render. That is it.

# Template

@input="renderPreview" means that when there is a change, the renderPreview method will be executed.

The rendered Markdown will be placed inside div under the textarea.

The textarea is bound to the input in the computed part. When there is an input, the set part will commit the changes. The get part is what the input will show.

Some Markdown input is already present as an example, but the method will not be called without any input change. Because of that, in the mounted part the method is called.

Finally, the methods contain the renderPreview method. This dispatches the renderPreview action, bringing the input to be passed.

# Store

The input has the example mentioned earlier. When there is a change, the renderPreview action is called. stringify the input for the body here.

renderedMd is taken from the response. commit that with commit("renderedMd", renderedMd);. The first renderedMd corresponds to the item in mutations, while the second one is the result to be passed.

There are 2 items in mutations:

  • updateInput to change the input state.
  • renderedMd to update the result.

getters return the state.

INFO

The getters here only return the state without any change, so you can actually get the state without getters in the component. It is my default to use a getter so that when I need to edit the state, I will not need to make lots of changes.

Last updated: 11/1/2020, 3:28:11 PM