Vuex 4 — Dynamic Module Registration and Logging

John Au-Yeung - Jan 26 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Vuex 4 is in beta and it’s subject to change.

Vuex is a popular state management library for Vue.

Vuex 4 is the version that’s made to work with Vue 3.

In this article, we’ll look at how to use Vuex 4 with Vue 3.

Dynamic Module Registration

We can register modules after the store it’s created with the store.registerModule method.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://unpkg.com/vuex@4.0.0-beta.4/dist/vuex.global.js"></script>
    <title>App</title>
  </head>
  <body>
    <div id="app">
      <button @click="increment">increment</button>
      <p>{{doubleCount}}</p>
    </div>
    <script>
      const moduleA = {
        state: () => ({
          count: 0
        }),
        mutations: {
          increment(state) {
            state.count++;
          }
        },
        getters: {
          doubleCount(state) {
            return state.count * 2;
          }
        }
      };

      const store = new Vuex.Store({});

      store.registerModule("moduleA", moduleA);
      const app = Vue.createApp({
        methods: {
          ...Vuex.mapMutations(["increment"])
        },
        computed: {
          ...Vuex.mapGetters(["doubleCount"])
        }
      });
      app.use(store);
      app.mount("#app");
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

We called the store.registerModule method with our module name and object to register the module.

Then we can use it in our components like any other module.

Plugins

We can create and use plugins in our store.

To do this, we just create a function that takes the store parameter and do something with it in the function

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://unpkg.com/vuex@4.0.0-beta.4/dist/vuex.global.js"></script>
    <title>App</title>
  </head>
  <body>
    <div id="app">
      <button @click="increment">increment</button>
      <p>{{doubleCount}}</p>
    </div>
    <script>
      const myPlugin = (store) => {
        store.subscribe((mutation, state) => {
          console.log(state);
        });
      };

      const store = new Vuex.Store({
        state: () => ({
          count: 0
        }),
        mutations: {
          increment(state) {
            state.count++;
          }
        },
        getters: {
          doubleCount(state) {
            return state.count * 2;
          }
        },
        plugins: [myPlugin]
      });

      const app = Vue.createApp({
        methods: {
          ...Vuex.mapMutations(["increment"])
        },
        computed: {
          ...Vuex.mapGetters(["doubleCount"])
        }
      });
      app.use(store);
      app.mount("#app");
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

We called subscribe with a callback that has the mutation and state parameters.

mutation has the data of the mutation being committed.

state has the current state of the store.

Built-in Logger Plugin

A logged plugin is provided by Vuex 4.

To use it, we call the createLogger function.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://unpkg.com/vuex@4.0.0-beta.4/dist/vuex.global.js"></script>
    <title>App</title>
  </head>
  <body>
    <div id="app">
      <button @click="increment">increment</button>
      <p>{{doubleCount}}</p>
    </div>
    <script>
      const store = new Vuex.Store({
        state: () => ({
          count: 0
        }),
        mutations: {
          increment(state) {
            state.count++;
          }
        },
        getters: {
          doubleCount(state) {
            return state.count * 2;
          }
        },
        plugins: [Vuex.createLogger()]
      });

      const app = Vue.createApp({
        methods: {
          ...Vuex.mapMutations(["increment"])
        },
        computed: {
          ...Vuex.mapGetters(["doubleCount"])
        }
      });
      app.use(store);
      app.mount("#app");
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

to use it.

We called the Vuex.createLogger method to return the logged plugin, which we pass into the plugins array.

The method takes an object with some properties which we can use as options.

They are various filters.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://unpkg.com/vuex@4.0.0-beta.4/dist/vuex.global.js"></script>
    <title>App</title>
  </head>
  <body>
    <div id="app">
      <button @click="increment">increment</button>
      <p>{{doubleCount}}</p>
    </div>
    <script>
      const store = new Vuex.Store({
        state: () => ({
          count: 0
        }),
        mutations: {
          increment(state) {
            state.count++;
          }
        },
        getters: {
          doubleCount(state) {
            return state.count * 2;
          }
        },
        plugins: [
          Vuex.createLogger({
            collapsed: false,
            filter(mutation, stateBefore, stateAfter) {
              return mutation.type !== "foo";
            },
            actionFilter(action, state) {
              return action.type !== "foo";
            },
            transformer(state) {
              return state.subTree;
            },
            mutationTransformer(mutation) {
              return mutation.type;
            },
            actionTransformer(action) {
              return action.type;
            },
            logActions: true,
            logMutations: true,
            logger: console
          })
        ]
      });

      const app = Vue.createApp({
        methods: {
          ...Vuex.mapMutations(["increment"])
        },
        computed: {
          ...Vuex.mapGetters(["doubleCount"])
        }
      });
      app.use(store);
      app.mount("#app");
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

to set the actions.

filter lets us filter the mutation or state to log.

actionFilter lets us filter actions by action or state properties.

transformer lets us transform the log output.

mutationTransformer lets us transform mutations log output.

actionTransformer lets us transform our actions log output.

logActions is a boolean to let us log actions if it’s true .

logMutations lets us log mutations if it’s true .

logger lets us set the logger we want to use to do the logging.

Conclusion

We can register Vuex 4 store modules dynamically.

Also, Vuex 4 comes with its own logger.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .