状态结构设计 #
设计原则 #
良好的状态结构设计是构建可维护 Vuex 应用的基础。
text
状态设计原则
├── 扁平化 ──────── 避免深层嵌套
├── 规范化 ──────── 消除数据冗余
├── 可预测 ──────── 状态变更可追踪
├── 可扩展 ──────── 便于添加新功能
└── 类型安全 ────── TypeScript 友好
扁平化设计 #
问题:深层嵌套 #
javascript
// 不推荐:深层嵌套结构
state: {
app: {
data: {
users: {
list: {
items: [
{ id: 1, name: 'John' }
]
}
}
}
}
}
// 访问困难
const user = this.$store.state.app.data.users.list.items[0]
解决:扁平化结构 #
javascript
// 推荐:扁平化结构
state: {
users: [
{ id: 1, name: 'John' }
]
}
// 访问简单
const user = this.$store.state.users[0]
规范化设计 #
问题:数据冗余 #
javascript
// 不推荐:数据冗余
state: {
posts: [
{
id: 1,
title: 'Post 1',
author: { id: 1, name: 'John', email: 'john@example.com' }
},
{
id: 2,
title: 'Post 2',
author: { id: 1, name: 'John', email: 'john@example.com' } // 重复
}
]
}
解决:规范化结构 #
javascript
// 推荐:规范化结构
state: {
posts: {
byId: {
1: { id: 1, title: 'Post 1', authorId: 1 },
2: { id: 2, title: 'Post 2', authorId: 1 }
},
allIds: [1, 2]
},
users: {
byId: {
1: { id: 1, name: 'John', email: 'john@example.com' }
},
allIds: [1]
}
}
// Getters 中关联数据
getters: {
postsWithAuthors: state => {
return state.posts.allIds.map(id => {
const post = state.posts.byId[id]
return {
...post,
author: state.users.byId[post.authorId]
}
})
}
}
实体关系设计 #
一对多关系 #
javascript
// 用户与文章:一个用户有多篇文章
state: {
users: {
byId: {
1: { id: 1, name: 'John' },
2: { id: 2, name: 'Jane' }
},
allIds: [1, 2]
},
posts: {
byId: {
101: { id: 101, title: 'Post 1', authorId: 1 },
102: { id: 102, title: 'Post 2', authorId: 1 },
103: { id: 103, title: 'Post 3', authorId: 2 }
},
allIds: [101, 102, 103]
}
}
getters: {
// 获取用户的所有文章
userPosts: state => userId => {
return state.posts.allIds
.map(id => state.posts.byId[id])
.filter(post => post.authorId === userId)
},
// 获取文章作者
postAuthor: state => postId => {
const post = state.posts.byId[postId]
return state.users.byId[post.authorId]
}
}
多对多关系 #
javascript
// 文章与标签:多对多关系
state: {
posts: {
byId: {
1: { id: 1, title: 'Post 1' },
2: { id: 2, title: 'Post 2' }
},
allIds: [1, 2]
},
tags: {
byId: {
1: { id: 1, name: 'Vue' },
2: { id: 2, name: 'React' },
3: { id: 3, name: 'JavaScript' }
},
allIds: [1, 2, 3]
},
// 关系表
postTags: [
{ postId: 1, tagId: 1 },
{ postId: 1, tagId: 3 },
{ postId: 2, tagId: 2 },
{ postId: 2, tagId: 3 }
]
}
getters: {
// 获取文章的所有标签
postTags: state => postId => {
return state.postTags
.filter(pt => pt.postId === postId)
.map(pt => state.tags.byId[pt.tagId])
},
// 获取标签下的所有文章
tagPosts: state => tagId => {
return state.postTags
.filter(pt => pt.tagId === tagId)
.map(pt => state.posts.byId[pt.postId])
}
}
按功能组织 #
模块化结构 #
javascript
// store/modules/user.js
export default {
namespaced: true,
state: {
profile: null,
preferences: {}
},
mutations: { /* ... */ },
actions: { /* ... */ },
getters: { /* ... */ }
}
// store/modules/products.js
export default {
namespaced: true,
state: {
items: {},
ids: [],
categories: []
},
mutations: { /* ... */ },
actions: { /* ... */ },
getters: { /* ... */ }
}
// store/modules/cart.js
export default {
namespaced: true,
state: {
items: [],
total: 0
},
mutations: { /* ... */ },
actions: { /* ... */ },
getters: { /* ... */ }
}
UI 状态分离 #
javascript
state: {
// 业务数据
entities: {
users: {},
posts: {},
comments: {}
},
// UI 状态
ui: {
loading: false,
error: null,
selectedUserId: null,
filter: 'all'
}
}
实战示例 #
电商应用状态设计 #
javascript
const store = createStore({
state: {
// 用户模块
user: {
profile: null,
addresses: [],
preferences: {}
},
// 产品模块
products: {
byId: {},
allIds: [],
categories: [],
featured: []
},
// 购物车模块
cart: {
items: [], // [{ productId, quantity, variant }]
couponCode: null
},
// 订单模块
orders: {
byId: {},
allIds: [],
current: null
},
// UI 状态
ui: {
isLoading: false,
error: null,
toast: null,
modal: null
}
},
getters: {
// 购物车商品详情
cartItems: state => {
return state.cart.items.map(item => ({
...state.products.byId[item.productId],
quantity: item.quantity,
variant: item.variant
}))
},
// 购物车总价
cartTotal: (state, getters) => {
return getters.cartItems.reduce((total, item) => {
return total + item.price * item.quantity
}, 0)
},
// 购物车商品数量
cartCount: state => {
return state.cart.items.reduce((count, item) => {
return count + item.quantity
}, 0)
}
}
})
博客应用状态设计 #
javascript
const store = createStore({
state: {
// 文章
posts: {
byId: {},
allIds: [],
currentPage: 1,
totalPages: 0
},
// 评论
comments: {
byId: {},
byPostId: {} // { postId: [commentId, ...] }
},
// 用户
users: {
byId: {},
currentUserId: null
},
// 标签
tags: {
byId: {},
allIds: []
},
// UI 状态
ui: {
loading: {
posts: false,
comments: false
},
error: null,
activeTag: null,
searchQuery: ''
}
},
getters: {
// 当前用户
currentUser: state => {
return state.users.byId[state.users.currentUserId]
},
// 文章列表
postList: state => {
return state.posts.allIds.map(id => state.posts.byId[id])
},
// 文章详情(含作者和评论)
postDetail: state => postId => {
const post = state.posts.byId[postId]
if (!post) return null
return {
...post,
author: state.users.byId[post.authorId],
comments: (state.comments.byPostId[postId] || [])
.map(id => state.comments.byId[id])
}
},
// 按标签筛选文章
postsByTag: state => tagId => {
return state.posts.allIds
.map(id => state.posts.byId[id])
.filter(post => post.tagIds.includes(tagId))
}
}
})
TypeScript 类型定义 #
typescript
// types/store.ts
// 用户类型
interface User {
id: number
name: string
email: string
}
// 文章类型
interface Post {
id: number
title: string
content: string
authorId: number
tagIds: number[]
createdAt: string
}
// 评论类型
interface Comment {
id: number
postId: number
userId: number
content: string
createdAt: string
}
// 规范化实体
interface EntityState<T> {
byId: Record<number, T>
allIds: number[]
}
// 根状态
interface RootState {
users: EntityState<User>
posts: EntityState<Post>
comments: EntityState<Comment>
ui: {
loading: boolean
error: string | null
}
}
总结 #
状态结构设计的关键点:
| 设计原则 | 说明 | 示例 |
|---|---|---|
| 扁平化 | 避免深层嵌套 | state.users 而非 state.app.data.users |
| 规范化 | 消除数据冗余 | 使用 byId 和 allIds |
| 模块化 | 按功能分割 | user、products、cart 模块 |
| 分离关注点 | 业务数据与 UI 状态分离 | entities 和 ui 分开 |
继续学习 Getter基础,了解如何创建派生状态。
最后更新:2026-03-28