Decomposing a Vuex module into distinct files with Nuxt: A step-by-step guide

In the official Nuxt documentation (here), it is mentioned that 'You can choose to divide a module file into separate files: state.js, actions.js, mutations.js, and getters.js'.

While there are examples of breaking down the Vuex store at the root level into individual files like state.js, actions.js, mutations.js, and getters.js, there is limited information on breaking down the modules themselves.

My current project structure looks like this:

     ├── assets
     ├── components
     └── store
           ├── moduleOne.js
           ├── moduleTwo.js
           └── etc...

What I want to achieve is:

     ├── assets
     ├── components
     └── store
           └── moduleOne
                 └── state.js
                 └── getters.js
                 └── mutations.js
                 └── actions.js
           └── moduleTwo
                └── etc...

To experiment with this structure, in /store/moduleOne/state.js I have defined the state as follows:

export const state = () => {
    return {
        test: 'test'
    }
};

And in /store/moduleOne/getters.js I have defined the getters like this:

export const getters = {
    getTest (state) {
        return state.test;
    }
}

When trying to access this in my component using

$store.getters['moduleOne/getters/getTest']
, it appears that the state is not accessible in the getters file. It seems to be searching for a local state, resulting in state.test being undefined.

Even attempting to import state from state.js into getters.js doesn't seem to work.

Is there anyone who has successfully implemented this modular breakdown of the store in Nuxt? If so, could you provide an example?

Answer №1

If you are using Nuxt version 2.1.0, and you want to implement a structured Vuex store with modules, here's how you can achieve it:

To begin, in your store/index.js, ensure that you set namespaced: true.

import Vuex from 'vuex';
import apiModule from './modules/api-logic';
import appModule from './modules/app-logic';

const createStore = () => {
  return new Vuex.Store({
    namespaced: true,
    modules: {
      appLogic: appModule,
      api: apiModule
    }
  });
};

export default createStore;

Module One

In the store/api-logic/index.js file of module one:

import actions from './actions';
import getters from './getters';
import mutations from './mutations';

const defaultState = {
  hello: 'Hello, I am the API module'
}

const state = typeof window !== 'undefined' && window.__INITIAL_STATE__ ? window.__INITIAL_STATE__.page : defaultState;

export default {
  state,
  actions,
  mutations,
  getters
}
... (Continue this format for Module Two and additional modules)

For communication between modules, such as triggering an action in app-logic from api-logic, utilize root: true. This directive allows cross-module interaction within the Vuex store.

(Complete instructions for implementing cross-module communication)

Finally, make sure to integrate these changes throughout your application components by utilizing computed properties, methods, and mapping functions provided by Vuex.

For a visual demonstration, refer to the example code repository at https://github.com/CMarzin/nuxt-vuex-modules.

Answer №2

With the latest version of Nuxt (2.14^), you no longer need to create specific files in your store root index.js file.

import Vuex from 'vuex';
import apiModule from './modules/api-logic';
import appModule from './modules/app-logic';

const createStore = () => {
  return new Vuex.Store({
    namespaced: true,
    modules: {
      appLogic: appModule,
      api: apiModule
    }
  });
};

export default createStore

Instead, you can simply leave your root index.js file as is or make any necessary modifications without the need for imports.

store/index.js

export const state = () => ({
  counter: 0
})

export const mutations = {
  increment(state) {
    state.counter++
  }
}

export const actions = {
   async nuxtServerInit({ state, commit }, { req }) {
   const cookies = this.$cookies.getAll() 
   ...
}

This setup makes it very straightforward and clean.

Folder structure

📦store
 ┣ 📂auth
 ┣ 📂utils
 ┣ 📂posts
 ┃ ┗ 📜actions.js
 ┃ ┗ 📜mutations.js
 ┃ ┗ 📜getters.js
 ┃ ┗ 📜index.js
 ┣ index.js

For instance, in store/posts/index.js, you only need to define the state function. No importing of actions, getters, or mutations is required.

export const state = () => ({ 
   comments: []
})

store/posts/actions.js

const actions = {
  async getPosts({ commit, state }, obj) {
    return new Promise((resolve, reject) => { 
       ...
    }
  }
}

export default actions

store/posts/mutations.js

 const mutations = {
    CLEAR_POST_IMAGE_CONTENT: (state) => {
       state.post_image_content = []
    }
 }
 
 export default mutations

store/posts/getters.js

const getters = {
    datatest: (state) => state.datatest,
    headlineFeatures: (state) => state.headlineFeatures,
}

export default getters

The result is similar to @CMarzin's answer but with a more streamlined approach.

Answer №3

Resolve the Problem

To address this issue, make use of default exports in your files to achieve the desired outcome (avoid using named exports except in the index.js file).

Illustrative Example

A practical example can be observed within the Nuxt.js test suite directly (accessible at https://github.com/nuxt/nuxt.js/tree/dev/test/fixtures/basic/store/foo).

If you execute the basic fixture and navigate to the /store page, you will observe the resulting output as follows:

https://i.sstatic.net/vASVy.png

The "repeated" contents within the module itself highlight that the divided values are given precedence. Otherwise, `getVal` would not return 10 and `state.val` would not be 4 instead of 2.

Code in store.vue:

<template>
  <div>
    <h1>{{ baz }}</h1>
    <br>
    <p>{{ $store.state.counter }}</p>
    <br>
    <h2>{{ getVal }}</h2>
    <br>
    <h3>{{ getBabVal }}</h3>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters('foo/bar', ['baz']),
    ...mapGetters('foo/blarg', ['getVal']),
    ...mapGetters('bab', ['getBabVal'])
  }
}
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to access the variable value chosen from a select dropdown inside a function and then assign it to a JavaScript variable outside of the function?

Below is the HTML and JavaScript code that I am working with: function changeResult() { x = document.getElementById("dropdown-list").value; console.log((x)); } var qq; <select id="dropdown-list" onchange="changeResult()"> <option value="4 ...

What is the process of utilizing marked plugins within a Vue3 project?

I attempted to integrate the marked plugin into my Vue.js applications. After installing [email protected], I did not encounter any issues during compilation. However, when I viewed the contents in the browser, nothing appeared. My Vue project was built u ...

Using forEach Loop with Promise.all in Node.js

I am seeking a solution for a task where I need to read a directory, copy its contents, and create a new file within that same directory. function createFiles(countryCode) { fs.readdir('./app/data', (err, directories) => { if (err) { ...

Angular Directive - introducing a fresh approach to two-way binding and enable "pass-by-value" functionality

In a previous question, I inquired about the possibility of incorporating an attribute on a directive to allow for values to be passed in various formats, such as: <my-directive att> //Evaluates to true <my-directive att="true"> ...

RequestDispatcher.forward() does not work when servlet is invoked through an Ajax POST request

My login page involves user authentication through the firebase and sending the request to a servlet. When I click the submit button with correct credentials, the firebase authentication works, the servlet is called but an error is displayed in the browser ...

The ion-datetime in Ionic 4 ensures that the floating label always remains visible, even when the input

When an ion-datetime field in Ionic 4 has no value, the label always floats as shown below. Here is my code snippet: <form [formGroup]="statusHandlerForm"> <ion-item class="input-container " align-items-center no-padding> <ion-la ...

Hiding the modal once the data has been successfully transmitted to the database

I am facing a challenge in my app where I need to close the modal after sending data to the database, but no matter what I try, I cannot seem to achieve it. Can anyone provide some guidance or assistance with this? :) <div class="container-fluid"&g ...

Issue: Module 'connect' is not found?

Hey there! I'm fairly new to the world of servers, and I've been learning by watching YouTube tutorials. Following one such tutorial, I installed 'connect' using npm in my project folder. Here's the structure of my project: serv ...

Employing require.js, one can integrate a distinctive form of non-concatenated dat.gui source. This allows for the seamless

Excuse the SEO-friendly title, but I want to ensure that everyone can access the issue I'm currently working on. For those interested in customizing the appearance of dat.gui, you will need to download the source and include it using require.js follow ...

What is the best way to recycle a variable in TypeScript?

I am trying to utilize my variable children for various scenarios: var children = []; if (folderPath == '/') { var children = rootFolder; } else { var children = folder.childs; } However, I keep receiving the following error message ...

forward to a different link following the backend script execution

I am facing a challenge with the signup.php page which includes a Facebook login button. The structure of the page is as follows: <?php if(!isset($_SESSION['logged_in'])) { echo '<div id="results">'; echo '<!-- ...

Unique Input Values in Forms

I'm encountering an issue with a basic HTML form connected to a PHP script for processing values. Despite thorough testing, the form is not functioning correctly. Upon inspecting the form markup, I discovered: <form id="delete_item_3_form" action ...

What steps are involved in implementing Local fonts in theme UI for Next JS?

I am currently developing an application using next JS with [theme-UI][1]. However, I need to implement local or custom fonts in my project and I'm unsure of how to do this. Below is the current theming setup: const theme = { fonts: { ...

Do I need to manually destroy the directive scope, or will Angular take care of it

I have a question about directives in Angular. Let's say we have a directive called "myDirective". Here is the corresponding HTML: <div my-directive> </div> When we remove this <div> element from the DOM, will Angular automatically ...

What is the process for changing the text in a text box when the tab key on the keyboard is pressed in

When a user types a name in this text box, it should be converted to a specific pattern. For example, if the user types Text@1, I want to print $[Text@1] instead of Text@1$[Text@1]. I have tried using the keyboard tab button with e.keyCode===9 and [\t ...

What is the best way to combine relative paths or create distinct identifiers for SVG files located within multiple layers of folders

I have a collection of icons exported from "Figma" organized in folders, and I'm using grunt-svgstore to create a sprite sheet. However, the result contains duplicated IDs even after trying 'allowDuplicateItems: false' and 'setUniqueIds ...

Struggles encountered when choosing the initial visible item

I have a set of 3 tabs, each with its own heading and content. However, I only want to display the tabs that the user selects by checking the corresponding checkboxes. There are 3 checkboxes, one for each tab. Below is the code snippet: //Function to ...

When using async functions in iterative processes

In my current setup, I am utilizing a for-each loop to handle a list and specifically require element n to be processed only after element n-1 has completed: let elements = ["item1", "item2", "item3"]; elements.forEach(function(element){ someAsyncFun ...

Node.js accepts JSON data sent via XMLHttpRequest

I have successfully implemented a post method using xmlhttprequest: var xhttp = new XMLHttpRequest() xhttp.onreadystatechange = function () { if (this.readyState === 4 && this.status === 200) { console.log('Request finished. Pro ...

Choosing an option from a PHP MySQL table based on a JavaScript value

I am attempting to create a select box that displays a value based on whether the database has a "yes" or "no" in the specified column. Despite my efforts, I am unable to identify any syntax errors causing this code snippet to not function properly. JavaSc ...