> For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt.

# Modules

Store lớn dồn vào một file sẽ khó quản lý. Modules chia store thành các phần độc lập, mỗi module có state, getters, mutations, actions riêng.

## Khai báo module

```js
const cart = {
  state: () => ({ items: [] }),
  getters: {
    itemCount(state) {
      return state.items.length
    }
  },
  mutations: {
    addItem(state, item) {
      state.items.push(item)
    }
  },
  actions: {
    async checkout({ state, commit }) {
      // ...
    }
  }
}

const user = {
  state: () => ({ profile: null })
}

export default new Vuex.Store({
  modules: { cart, user }
})
```

State của module nên là function (giống `data` của component) để tránh share khi tái sử dụng module.

## Truy cập state module

State module nằm lồng dưới tên module trong store state.

```js
this.$store.state.cart.items
this.$store.state.user.profile
```

Getters, mutations, actions mặc định đăng ký ở namespace toàn cục (gọi không cần tên module). Dễ trùng tên giữa các module.

## Namespaced modules

Đặt `namespaced: true` để getters/mutations/actions của module có tiền tố riêng. Đây là cách nên dùng cho module nghiệp vụ.

```js
const cart = {
  namespaced: true,
  state: () => ({ items: [] }),
  getters: {
    itemCount: state => state.items.length
  },
  mutations: {
    addItem(state, item) {
      state.items.push(item)
    }
  },
  actions: {
    checkout({ commit }) { /* ... */ }
  }
}
```

Gọi với tiền tố `cart/`:

```js
this.$store.getters['cart/itemCount']
this.$store.commit('cart/addItem', item)
this.$store.dispatch('cart/checkout')
```

## map helpers với namespace

Truyền namespace làm tham số đầu cho gọn.

```js
import { mapState, mapGetters, mapActions } from 'vuex'

export default {
  computed: {
    ...mapState('cart', ['items']),
    ...mapGetters('cart', ['itemCount'])
  },
  methods: {
    ...mapActions('cart', ['checkout'])
  }
}
```

Hoặc dùng `createNamespacedHelpers`:

```js
import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('cart')

export default {
  computed: { ...mapState(['items']) },
  methods: { ...mapActions(['checkout']) }
}
```

## Truy cập gốc từ trong module

Trong action/getter của module namespaced, truy cập state và getter gốc qua tham số bổ sung.

```js
actions: {
  someAction({ commit, dispatch, rootState, rootGetters }) {
    // commit mutation toàn cục
    commit('someGlobalMutation', null, { root: true })
    // dispatch action toàn cục
    dispatch('someGlobalAction', null, { root: true })
  }
}
```

```js
getters: {
  // getter nhận thêm rootState, rootGetters
  example(state, getters, rootState, rootGetters) {
    return state.items.length + rootState.user.bonus
  }
}
```

## Cấu trúc thư mục gợi ý

Project lớn tách mỗi module ra file riêng.

```
store/
├── index.js          # tạo store, gom modules
├── modules/
│   ├── cart.js
│   ├── user.js
│   └── products.js
└── mutation-types.js
```

## Tips cho AEM

Mỗi nhóm chức năng (cart, user, search) làm một namespaced module. Khi nhiều AEM component dùng chung store, mỗi component chỉ map đúng module nó cần, tránh trùng tên và giảm coupling. Module `user` có thể nhận dữ liệu khởi tạo từ Sling Model server-side, các module khác gọi API qua action.
