Как добиться нормализации состояния в Vuex? - PullRequest
1 голос
/ 28 марта 2019

Я разрабатываю приложение, также использующее 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)
},

В этой ситуации необходимо сбросить состояние, иначе у вас будут повторяться / старые значения каждый раз, когда вы покидаете страницу и повторно переносите страницу. Это немного раздражает и более предрасположено к ошибкам или непоследовательному поведению.

Заключение Как вы, ребята, справляетесь с такими сценариями и советами / передовым опытом? Ответы очень ценятся, так как я застрял на этих вещах.

Кроме того, я стараюсь избегать сторонних библиотек, таких как Vue ORM, normalizr и т. Д., Потому что потребности не так сложны.

Спасибо,

PS: в коде могут быть ошибки, так как я написал его без тестирования, пожалуйста, обратите внимание на общую картину.

1 Ответ

0 голосов
/ 28 марта 2019

Что ж, чтобы избежать случайной сложности в приведенном ниже состоянии, есть пункты, о которых нужно позаботиться при нормализации состояния.

Как указано в официальном Redux документы

  1. Каждый тип данных получает свою «таблицу» в состоянии.
  2. Каждая «таблица данных» должна хранить отдельные элементы в объекте с идентификаторами элементов в качестве ключей и самими элементами в качестве значений.
  3. Любые ссылки на отдельные элементы должны быть сделаны путем сохранения идентификатора элемента.
  4. Для указания порядка следует использовать массивы идентификаторов.

Теперь с примером выше, чтобы удалить избыточность из данных. Вы можете использовать каждую таблицу для каждой информации, такой как 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"]
  }
}

Таким образом, мы можем убедиться, что больше компонентов подключено и отвечает за поиск и обслуживание своего собственного набора данных, а не у каждого компонента большой набор данных и передача данных в компонент chilren.

ОБНОВЛЕННЫЙ ОТВЕТ

Поскольку данные были нормализованы в соответствии с компонентом, передайте объекты из родительского компонента одним действием и как часть нормализации, можно получить следующие преимущества.

  1. Ускоренный доступ к данным, больше не нужно перебирать массивы или вложенные объекты.
  2. Слабая связь между компонентами.
  3. Каждый компонент имеет свое место в магазине, следовательно, есть одна точка правды.

Надеюсь, это поможет!

...