2015-08-21 6 views
46

Каков наилучший/правильный способ обновления вложенного массива данных в магазине с помощью сокращений?Обновление вложенных данных в магазине redux

Мой магазин выглядит следующим образом:

{ 
    items:{ 
     1: { 
      id: 1, 
      key: "value", 
      links: [ 
       { 
        id: 10001 
        data: "some more stuff" 
       }, 
       ... 
      ] 
     }, 
     ... 
    } 
} 

У меня есть пара асинхронных действий, которые полностью обновляет items объект, но у меня есть еще одна пара действий, которые я хочу, чтобы обновить определенный links массив.

Мой редуктор в настоящее время выглядит следующим образом, но я не уверен, что это правильный подход:

switch (action.type) { 
    case RESOURCE_TYPE_LINK_ADD_SUCCESS: 
     // TODO: check whether the following is acceptable or should we create a new one? 
     state.items[action.resourceTypeId].isSourceOf.push(action.resourceTypeLink); 
     return Object.assign({}, state, { 
     items: state.items, 
     }); 
    } 

ответ

49

РЕАКТ update() immutability helper это удобный способ для создания обновленной версии простого старого объекта JavaScript не мутирует его ,

Вы передаете исходный объект для обновления и объект, описывающий пути к частям, которые необходимо обновить, и изменения, которые необходимо выполнить.

например, если действие было id и link свойства, и вы хотели, чтобы подтолкнуть link на массив ссылок в элементе шпонкой с id:

var update = require('react/lib/update') 

// ... 

return update(state, { 
    items: { 
    [action.id]: { 
     links: {$push: action.link} 
    } 
    } 
}) 

(пример использует ES6 вычисленного имя свойства для action.id)

+5

Обратите внимание, что update() устарел в пользу https://github.com/kolodny/immutability-helper –

+0

Мне любопытно, почему вы не решили использовать 'Object.assign()'? – HussienK

+0

@HussienK Разве 'Object.assign' выполняет мелкую копию? –

57

Jonny's answer правильный (никогда не изменяйте состояние, данное вам!), Но я хотел добавить к нему еще одну точку. Если у всех ваших объектов есть идентификаторы, обычно это плохая идея, чтобы сохранить форму состояния вложенной.

Это:

{ 
    items: { 
    1: { 
     id: 1, 
     links: [{ 
     id: 10001 
     }] 
    } 
    } 
} 

это форма, которая трудно обновить.

Этого не должно быть! Вместо этого вы можете хранить его, как это:

{ 
    items: { 
    1: { 
     id: 1, 
     links: [10001] 
    } 
    }, 
    links: { 
    10001: { 
     id: 10001 
    } 
    } 
} 

Это гораздо проще для обновления, потому что есть только одна каноническая копия любого субъекта. Если вам нужно разрешить пользователю «редактировать ссылку», есть только одно место, где необходимо обновить его, и оно полностью не зависит от items или чего-либо другого, ссылающегося на links.

Чтобы получить ответы API в такой форме, вы можете использовать normalizr. После того, как ваши объекты внутри действий серверов нормализуются, вы можете написать простой редуктор, который объединяет их в текущее состояние:

import merge from 'lodash/object/merge'; 

function entities(state = { items: {}, links: {} }, action) { 
    if (action.response && action.response.entities) { 
    return merge({}, state, action.response.entities); 
    } 

    return state; 
} 

Пожалуйста, см Redux real-world примера для демонстрации такого подхода.

+0

Я использую normalizr, но мне также нужны элементы в том же порядке, что и в ответе API. Я думал о внедрении «связанного списка» с использованием идентификаторов объектов, но мне интересно, есть ли вместо этого лучший подход. –

+0

@hisa_py Вы хотите сохранить массив идентификаторов отдельно. И примеры «реального мира» и «корзины покупок» в репозитории Redux делают это. –

+1

Thx @ Dan ... Приятно и просто ... Теперь я помню, что видел это раньше в примерах –

Смежные вопросы