如何在React本机Redux的reducer中向数组添加元素?


140

如何arr[]在reducer的redux状态数组中添加元素?我正在这样做-

import {ADD_ITEM} from '../Actions/UserActions'
const initialUserState = {
    arr:[]
}

export default function userState(state = initialUserState, action)
{
    console.log(arr);
    switch (action.type)
    {
        case ADD_ITEM: 
            return { 
                      ...state,
                      arr: state.arr.push([action.newItem])
                   }

        default:
            return state
    }
}

Answers:


361

两种不同的选项可将项目添加到数组而无需突变

case ADD_ITEM :
    return { 
        ...state,
        arr: [...state.arr, action.newItem]
    }

要么

case ADD_ITEM :
    return { 
        ...state,
        arr: state.arr.concat(action.newItem)
    }

1
应该认为哪一个更可取?
sapht

19
@sapht,如果您要用ES6编写代码,则首选第一个更易读和优雅的IMO。
Yadhu Kiran'5

5
另外,第一个不是纯净的,第二个不是纯净的。来自Redux的文档:“非常重要的一点是,Reducer保持纯净。在reducer内永远不应该做的事情:1.更改其变数; 2.执行副作用,如API调用和路由转换; 3.调用非纯函数,例如Date.now()或Math.random()。”
迷人的机器人

您好,@YadhuKiran您能向我解释一下为什么我们在数组的第二个索引中添加了新值,但我不太理解吗?arr: [...state.arr, why here?]
奥利弗·D

@OliverD,如上使用散布语法时,它不是在第二个索引处插入元素,而是在最后一个索引处插入元素。与此相反,[action.newItem, ...state.arr]将元素插入第一个位置。
Yadhu Kiran

22

push不会返回数组,而是返回数组的长度(docs),因此您正在执行的操作是将数组替换为其长度,从而丢失对数组的唯一引用。试试这个:

import {ADD_ITEM} from '../Actions/UserActions'
const initialUserState = {

    arr:[]
}

export default function userState(state = initialUserState, action){
     console.log(arr);
     switch (action.type){
        case ADD_ITEM :
          return { 
             ...state,
             arr:[...state.arr, action.newItem]
        }

        default:return state
     }
}

1
任何人都可以用Object.assign状态内部数组的变化来回答这个问题吗?
Vennesa '18

2
为什么需要Object.assign?它用于对象,本质上是同一件事。arr:[...state.arr, action.newItem]您可以在那里使用obj: Object.assign({}, state.obj, action.newItem,前提是objnewItem是对象。如果您想在整个州做到这一点,就可以这样做Object.assign({}, state, {arr: [..state.arr, action.newItem]})
martinarroyo

1
@martinarroyo,谢谢,我这样做了:var obj = { isLoading: true, data: ['a', 'b', 'c', 'd'] } var newObj = Object.assign({}, obj, { data: [...obj.data, 'e'] });它给了我:{ isLoading: true, data: [ 'a', 'b', 'c', 'd', 'e' ] }对于newObj来说,它足以满足我的需求。但是我想在不使用传播运算符的情况下使用Object.assign来产生相同的结果。那可能吗?
Vennesa '18

1
@Vennesa我想[].concat(obj.data, ['e'])如果您不想使用ES6功能,可以将其替换为。Object.assign用于对象,尽管它不会给您在数组上使用它的任何错误,但是结果不是数组的串联。如果尝试Object.assign({}, [1, 2, 3], [4]),您将得到[4, 2, 3]结果。
martinarroyo

13

如果需要插入数组中的特定位置,可以执行以下操作:

case ADD_ITEM :
    return { 
        ...state,
        arr: [
            ...state.arr.slice(0, action.pos),
            action.newItem,
            ...state.arr.slice(action.pos),
        ],
    }

我在这里跌跌撞撞...虽然这个答案并不完全适合上面的问题。不过,这正是我所要的。我正在寻找一种在数组的特定索引中插入对象的方法。因此,我对答案投了赞成票。这非常有帮助,为我节省了一些时间。谢谢!
波斯

0

我有一个样本

import * as types from '../../helpers/ActionTypes';

var initialState = {
  changedValues: {}
};
const quickEdit = (state = initialState, action) => {

  switch (action.type) {

    case types.PRODUCT_QUICKEDIT:
      {
        const item = action.item;
        const changedValues = {
          ...state.changedValues,
          [item.id]: item,
        };

        return {
          ...state,
          loading: true,
          changedValues: changedValues,
        };
      }
    default:
      {
        return state;
      }
  }
};

export default quickEdit;

1
添加一些说明
SPatel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.