vue.js - Vuex中如何实现状态归一化?

标签 vue.js vuejs2 vuex vue-router

我正在开发一个也使用 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'}, {...}],
    {...}
] 

假设 commentsusers 的子模块:

选项 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 中所述

  1. Each type of data gets its own "table" in the state.
  2. 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.
  3. Any references to individual items should be done by storing the item's ID.
  4. 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"]
  }
}

通过这样做,我们可以确保连接更多的组件并负责查找和维护自己的数据集,而不是每个组件都有一个大数据集并将数据传递给子组件。

更新答案

由于数据已根据组件进行了规范化,因此通过单个操作从父组件传递实体并作为规范化的一部分,可以获得以下好处。

  1. Faster data access, no more iterating over arrays or nested objects.
  2. Loose coupling between components.
  3. 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/

相关文章:

vue.js - v-bind href 重定向到本地主机而不是实际链接

vuejs2 - 为什么 v-bind 是单向数据绑定(bind),而 v-for 可以更新 vue.js 中子组件的数据?

javascript - vuex 操作返回 false 时出现奇怪的控制台错误

vue.js - 如何从vuex Action 中调用bootstrap-vue模态和 toast ?

javascript - 使用 VeeValidate,我如何查看某个字段是否已被触摸并且是否有效?

javascript - 如何在 nuxt.js 上从子组件获取值到父组件?

javascript - 如何在 vue.js 中处理用户提供的数据中的 ' ?

javascript - Axios 拦截器 token header 存在于配置中但不存在于请求 header 中

javascript - 在 Parent 和 Grandchildren Vue 2 之间使用同步修饰符

javascript - 如何重置/删除 vuex 存储数据?