我正在开发一个也使用 Vuex 的应用程序,只是遇到了处理嵌套对象会很痛苦的情况,所以我试图尽可能地标准化(展平)状态,如下例所示:
users: {
1234: { ... },
46473: { name: 'Tom', topics: [345, 3456] }
},
userList: [46473, 1234]
我的问题是: 当您的 API 响应如下 时,实现上述目标的“最佳”方法是什么:
data: [
{id: 'u_0001', name: 'John', coments: [{id: 'c_001', body: 'Lorem Ipsum'}, {...}],
{id: 'u_0002', name: 'Jane', coments: [{id: 'c_002', body: 'Lorem Ipsum'}, {...}],
{...}
]
假设
comments
是 users
的子模块:选项 1:
// action on the user module
export const users = ({ commit, state }, users) => {
commit(SET_USERS, users)
commit('comments/SET_COMMENTS', users)
}
// mutation on the user module
[types.SET_USERS] (state, users) {
state.users = users.reduce((obj, user) => {
obj[user.id] = {
id: user.id,
name: user.name,
comments: user.comments.map(comment => comment.id)
}
return obj
}, {})
state.userIds = users.map(user => user.id)
},
// mutation on the comments module
[types.SET_COMMENTS] (state, users) {
let allComments = []
users.forEach(user => {
let comments = user.comments.reduce((obj, comment) => {
obj[comment.id] = comment
return obj
}, {})
allComments.push(comments)
})
state.comments = ...allComments
},
IMO这个选项很好,因为您不必担心每次更改页面时重置状态(SPA/Vue-Router),避免由于某种原因
id: u_001
不再存在的情况,因为每次突变都会覆盖状态被调用,但是将 users array
传递给两个突变感觉很奇怪。选项 2:
// action on the user module
export const users = ({ commit, state }, users) => {
// Here you would have to reset the state first (I think)
// commit(RESET)
users.forEach(user => {
commit(SET_USER, user)
commit('comments/SET_COMMENTS', user.comments)
})
}
// mutation on the user module
[types.SET_USER] (state, user) {
state.users[user.id] = {
id: user.id,
name: user.name,
comments: user.comments.map(comment => comment.id)
}
state.userIds.push(user.id)
},
// mutation on the comments module
[types.SET_COMMENTS] (state, comments) {
comments.forEach(comment => {
Vue.set(state.comments, comment.id, comment)
})
state.commentsIds.push(...comments.map(comment => comment.id)
},
在这种情况下,需要重置状态,否则每次离开并重新租用页面时都会有重复/旧值。 Wich 有点烦人,而且更容易出现错误或不一致的行为。
结论
你们是如何应对这种情况和建议/最佳实践的?非常感谢答案,因为我坚持这些事情。
另外,我试图避免使用 Vue ORM、normalizr 等 3r 方库,因为需求并不那么复杂。
谢谢,
PS:代码可能有错误,因为我只是写了没有测试,请关注大局。
最佳答案
好吧,为了避免以下状态中的意外复杂性,是在进行状态归一化时需要注意的点。
正如官方 Redux docs 中所述
- Each type of data gets its own "table" in the state.
- Each "data table" should store the individual items in an object, with the IDs of the items as keys and the items themselves as the values.
- Any references to individual items should be done by storing the item's ID.
- Arrays of IDs should be used to indicate ordering.
现在使用上面的示例,从数据中删除冗余。您可以将每个表用于每个信息,例如
users
, comments
等等。{
'users': {
byId : {
"user1" : {
username : "user1",
name : "User 1",
},
"user2" : {
username : "user2",
name : "User 2",
},
...
},
allIds : ["user1", "user2", ..]
},
'comments': {
byId : {
"comment1" : {
id : "comment1",
author : "user2",
body: 'Lorem Ipsum'
},
"comment2" : {
id : "comment2",
author : "user3",
body: 'Lorem Ipsum'
},
allIds : ["comment1", "comment2"]
}
}
通过这样做,我们可以确保连接更多的组件并负责查找和维护自己的数据集,而不是每个组件都有一个大数据集并将数据传递给子组件。
更新答案
由于数据已根据组件进行了规范化,因此通过单个操作从父组件传递实体并作为规范化的一部分,可以获得以下好处。
- Faster data access, no more iterating over arrays or nested objects.
- Loose coupling between components.
- Each component has its own place in the store, hence there is a single point of truth.
希望这可以帮助!
关于vue.js - Vuex中如何实现状态归一化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55387562/