Обновление вложенного неизменяемого состояния (приставка) - PullRequest
0 голосов
/ 25 октября 2018

Я ищу, чтобы добавить новый объект предмета в категорию в редукторе.Редуктор получает индекс категории и объект нового элемента.

Кто-нибудь знает лучший способ неизменного обновления состояния с такой структурой данных:

const initialState = {    
    categories: [
        {
            id: 1,
            name: "vegetables",
            items: [
                {name: "potatoes", id: Math.floor(Math.random() * 99999)},
                {name: "carrots", id: Math.floor(Math.random() * 99999)}
            ] 
        },
        {
            id: 2,
            name: "dairy",
            items: [
                {name: "milk", id: Math.floor(Math.random() * 99999)},
                {name: "cheese", id: Math.floor(Math.random() * 99999)}
            ] 
        },
        {
            id: 3,
            name: "meat",
            items: [
                {name: "chicken", id: Math.floor(Math.random() * 99999)}
            ] 
        }
    ]
}

Или лучше использоватьвнешний пакет, такой как immutable.js?

Есть много других похожих вопросов о стековом потоке, но ни один из них не имеет такой же структуры.

Обновление

Остальная часть редуктора выглядит следующим образом:

const shoppingItemsReducer = (state = initialState, action) => {

    switch (action.type) {
        case ADD_SHOPPING_ITEM:

        const categories = [...state.categories];


     categories[action.selectedCategoryIndex].items.push(action.newItemObj);

            return {
                ...state,
                categories
            }
        default:
            return state
    }

}

Использование push работает нормально, но оно изменяет состояние

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Вы можете сделать следующее, не используя push

const initialState = {    
    categories: [
        {
            id: 1,
            name: "vegetables",
            items: [
                {name: "potatoes", id: Math.floor(Math.random() * 99999)},
                {name: "carrots", id: Math.floor(Math.random() * 99999)}
            ] 
        },
        {
            id: 2,
            name: "dairy",
            items: [
                {name: "milk", id: Math.floor(Math.random() * 99999)},
                {name: "cheese", id: Math.floor(Math.random() * 99999)}
            ] 
        },
        {
            id: 3,
            name: "meat",
            items: [
                {name: "chicken", id: Math.floor(Math.random() * 99999)}
            ] 
        }
    ]
}

const categoryId = 2; // categoy want to update
cosnt newItem = {name: "Butter", id: Math.floor(Math.random() * 99999)}

const newState = {
  ...initialState, // or state
  categories: initialState.categories.map(category => {
    if(category.id === categoryId) {
      return {
        ...category,
        items: [
          ...category.items,
          newItem
        ]
      }
    }
    return category;
  )
}
0 голосов
/ 25 октября 2018

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

Однако объекты и массивы всегда передаются по ссылке.Так что если вы передадите Object или Array другой переменной, они оба будут ссылаться на один и тот же исходный объект.Если бы вы изменили любую из этих переменных, ссылающуюся на оригинал, это также изменило бы исходный объект / массив.

Чтобы обойти это, вам нужно создать новую копиюМассив.Вы можете сделать это в простом javascript следующим образом:

const initialState = [
    {
        id: 1,
        name: "category 1",
        items: [
            {name: "item 1", id: 1},
            {name: "item 2", id: 2}
        ] 
    },
    {
        id: 2,
        name: "category 2",
        items: [
            {name: "item 3", id: 3},
            {name: "item 4", id: 4}
        ] 
    },
    {
        id: 3,
        name: "category 3",
        items: [
            {name: "item 5", id: 5},
            {name: "item 6", id: 6}
        ] 
    }
]


const newState = [...initialState, newDataObject]

newState - это вновь созданный массив с копиями initialState с newDataObject, помещенным в последний индекс массива newState.

РЕДАКТИРОВАТЬ: Я видел, как вы обновили свой вопрос с вашим редукторным редуктором.В настоящее время вы возвращаете объект, который ссылается на начальное состояние:

    return {
        ...state,
        categories
    }

Вместо этого он должен возвращать новый объект с категориями, поднятыми к нему.Вы можете использовать es6 Object.assign() для объединения двух объектов, и он вернет совершенно новый Объект, содержащий оба.

Измените выписку о возврате на:

        return Object.assign({}, state, categories)
...