Tổ chức store trong dự án lớn với Vue.js
Trong các ứng dụng Vue.js lớn, việc tổ chức store hợp lý giúp dễ dàng mở rộng, bảo trì và tối ưu hiệu suất.
Mục tiêu bài học:
- Hiểu cách chia nhỏ store thành nhiều module để quản lý tốt hơn.
- Cấu trúc thư mục tối ưu khi làm việc với Vuex / Pinia.
- Sử dụng mapState, mapGetters, mapMutations, mapActions để truy cập store nhanh chóng trong Component.
- Thực hành: Xây dựng hệ thống quản lý giỏ hàng với Vuex / Pinia.

Tổ chức store
1. Chia nhỏ store thành nhiều module
Tại sao cần chia nhỏ store?
- Giúp dễ quản lý khi dự án mở rộng.
- Giảm tính phụ thuộc giữa các phần trong store.
- Tăng hiệu suất bằng cách chỉ tải những module cần thiết.
Chia store thành nhiều module trong Vuex
// store/modules/products.js
export default {
namespaced: true,
state: {
products: []
},
mutations: {
setProducts(state, products) {
state.products = products;
}
},
actions: {
async fetchProducts({ commit }) {
const response = await fetch("https://api.example.com/products");
const data = await response.json();
commit("setProducts", data);
}
},
getters: {
productCount: (state) => state.products.length
}
};
// store/modules/cart.js
export default {
namespaced: true,
state: {
cart: []
},
mutations: {
addToCart(state, product) {
state.cart.push(product);
}
},
getters: {
cartTotal: (state) => state.cart.length
}
};
// store/index.js (import các module vào store chính)
import Vue from "vue";
import Vuex from "vuex";
import products from "./modules/products";
import cart from "./modules/cart";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
products,
cart
}
});
Chia store thành nhiều module trong Pinia
// store/products.js
import { defineStore } from "pinia";
export const useProductStore = defineStore("product", {
state: () => ({
products: []
}),
actions: {
async fetchProducts() {
const response = await fetch("https://api.example.com/products");
this.products = await response.json();
}
},
getters: {
productCount: (state) => state.products.length
}
});
// store/cart.js
import { defineStore } from "pinia";
export const useCartStore = defineStore("cart", {
state: () => ({
cart: []
}),
actions: {
addToCart(product) {
this.cart.push(product);
}
},
getters: {
cartTotal: (state) => state.cart.length
}
});
Sử dụng store trong Component:
<template>
<div>
<h2>Tổng số sản phẩm: {{ productCount }}</h2>
<button @click="fetchProducts">Tải sản phẩm</button>
</div>
</template>
<script>
import { useProductStore } from "../store/products";
import { storeToRefs } from "pinia";
export default {
setup() {
const store = useProductStore();
return { fetchProducts: store.fetchProducts, ...storeToRefs(store) };
}
};
</script>
2. Cấu trúc thư mục tối ưu khi làm việc với Vuex / Pinia
Cấu trúc thư mục hợp lý giúp dễ dàng mở rộng
src/
│── store/
│ ├── index.js # Store chính (Vuex)
│ ├── products.js # Store sản phẩm
│ ├── cart.js # Store giỏ hàng
│── components/
│ ├── ProductList.vue
│ ├── Cart.vue
│── views/
│ ├── Home.vue
│ ├── Checkout.vue
Với Pinia, không cần index.js
, mỗi store là một file độc lập.
3. Sử dụng mapState, mapGetters, mapMutations, mapActions
Các hàm giúp dễ dàng truy cập store trong Component Vue
Hàm | Dùng để | Vuex | Pinia |
---|---|---|---|
mapState | Lấy state từ store | Có | Không (Dùng storeToRefs) |
mapGetters | Lấy getters từ store | Có | Không (Dùng storeToRefs) |
mapMutations | Gọi mutations | Có | Không (Dùng actions trực tiếp) |
mapActions | Gọi actions | Có | Có |
Ví dụ sử dụng trong Vuex
<template>
<div>
<h2>Tổng số sản phẩm: {{ productCount }}</h2>
<button @click="fetchProducts">Tải sản phẩm</button>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions } from "vuex";
export default {
computed: {
...mapState("products", ["products"]),
...mapGetters("products", ["productCount"])
},
methods: {
...mapActions("products", ["fetchProducts"])
}
};
</script>
Ví dụ sử dụng trong Pinia
<template>
<div>
<h2>Tổng số sản phẩm: {{ productCount }}</h2>
<button @click="fetchProducts">Tải sản phẩm</button>
</div>
</template>
<script>
import { useProductStore } from "../store/products";
import { storeToRefs } from "pinia";
export default {
setup() {
const store = useProductStore();
return { fetchProducts: store.fetchProducts, ...storeToRefs(store) };
}
};
</script>
Thực hành: Xây dựng hệ thống quản lý giỏ hàng với Vuex / Pinia
Mô tả bài thực hành
-
Tạo store
cart
để quản lý giỏ hàng. - Thêm sản phẩm vào giỏ hàng bằng action.
- Hiển thị số lượng sản phẩm trong giỏ hàng.
Xây dựng store giỏ hàng (Vuex)
export default {
namespaced: true,
state: {
cart: []
},
mutations: {
addToCart(state, product) {
state.cart.push(product);
}
},
getters: {
cartTotal: (state) => state.cart.length
}
};
Xây dựng store giỏ hàng (Pinia)
export const useCartStore = defineStore("cart", {
state: () => ({
cart: []
}),
actions: {
addToCart(product) {
this.cart.push(product);
}
},
getters: {
cartTotal: (state) => state.cart.length
}
});
Sử dụng store trong Component Vue
<template>
<div>
<h2>Giỏ hàng: {{ cartTotal }} sản phẩm</h2>
<button @click="addToCart({ id: 1, name: 'Laptop' })">Thêm Laptop</button>
</div>
</template>
<script>
import { useCartStore } from "../store/cart";
import { storeToRefs } from "pinia";
export default {
setup() {
const store = useCartStore();
return { addToCart: store.addToCart, ...storeToRefs(store) };
}
};
</script>
Kết luận
Tóm tắt kiến thức quan trọng:
- Chia store thành nhiều module để quản lý tốt hơn.
- Cấu trúc thư mục hợp lý giúp dễ mở rộng.
- mapState, mapGetters, mapMutations, mapActions giúp code gọn hơn.
- Thực hành: Xây dựng hệ thống quản lý giỏ hàng.

Với hơn 10 năm kinh nghiệm lập trình web và từng làm việc với nhiều framework, ngôn ngữ như PHP, JavaScript, React, jQuery, CSS, HTML, CakePHP, Laravel..., tôi hy vọng những kiến thức được chia sẻ tại đây sẽ hữu ích và thiết thực cho các bạn.
Xem thêm

Chào, tôi là Vũ. Đây là blog hướng dẫn lập trình của tôi.
Liên hệ công việc qua email dưới đây.
lhvuctu@gmail.com