更改数组项目的最佳方法是什么?

Sin*_*pcs 6 immutability redux

在Redux中更改商店数组元素的最佳方法是什么?我有这3个工作解决方案.哪个是最好的?我认为前两种解决方案正在改变国家.这是真的吗?如果您有更好的解决方案,我会很感激.

在这个例子中我有一个订单列表,我想增加列表中一个订单的数量.我将此订单索引作为orderIndex传递.

第一种方式:

let order = state[action.orderIndex];
order.quantity++;
return Object.assign([],order);
Run Code Online (Sandbox Code Playgroud)

第二种方式:

let order= Object.assign([],state);
order[action.orderIndex].quantity++;
return Object.assign([],order);
Run Code Online (Sandbox Code Playgroud)

第三种方式:

return Object.assign([],state.map(
            (order,index) => (index==action.orderIndex) ? {...order,quantity:order.quantity+1} : order)
        );
Run Code Online (Sandbox Code Playgroud)

我有另一个解决方案,但它返回一个对象,我不知道如何在此解决方案中返回一个数组.:

            return {...state,[action.orderIndex]:{...state[action.orderIndex],quantity:state[action.orderIndex].quantity+1}};
Run Code Online (Sandbox Code Playgroud)

Mar*_*ams 11

如果您正在修改数组中的项目,请使用新值创建一个新项目,然后返回一个新数组,将要修改的元素前后的元素切片并插入到中间.使用ES6扩展语法,您可以执行以下操作:

var newArray = [
  ...originalArray.slice(0, indexOfAmendedItem),
  amendedItem,
  ...originalArray.slice(indexOfAmendedItem + 1)
];
Run Code Online (Sandbox Code Playgroud)

看这个:

https://egghead.io/lessons/javascript-redux-avoiding-array-mutations-with-concat-slice-and-spread

它解释得非常出色.


DDS*_*DDS 5

第一个修改原始顺序,即突变.这违反了Redux商店的不变性.

第二个是数组的副本,但数组中的对象仍然是原始顺序.它们只是引用与原始数组相同的实例.因此,当您在下一行修改其中一个时,您正在改变Redux状态.

第三种方式是一个有趣的方法,因为即使你没有改变状态,它也可以简化.

return state.map(order => (index==action.orderIndex) ? {...order, quantity: order.quantity+1} : order);
Run Code Online (Sandbox Code Playgroud)

因为map函数已经返回一个新数组,所以不需要调用Object.assign.

第三个版本有效,因为您引用了所有未修改的订单,并仅为您要更改的项目创建新订单.由于不允许变异,因此您需要创建一个新对象.

现在,ES6语法可能令人困惑.你可以完全没有ES6使它工作(除了Object.assign你可以用extend下划线替换它.重要的是没有使用新的语法).

// copy the list so we can modify the copy without mutating the original
// it is important to realize that even though the list is brand new
// the items inside are still the original orders
var newOrders = state.slice();
// grab the old order we'd like to modify
// note that we could have grabbed it from state as well
// they are one and the same object
var oldOrder = newOrders[action.orderIndex];
// this takes a new object and copies all properties of oldOrder into it
// it then copies all properties of the final object into it
// the final object has only our new property
// we could have multiple properties there if we needed
var newOrder = Object.assign({}, oldOrder, { quantity: oldOrder.quantity + 1 });
// now we just replace the old order with the new one
// remember it's okay to modify the list since we copied it first
newOrders[action.orderIndex] = newOrder;
return newOrders;
Run Code Online (Sandbox Code Playgroud)

或者,您可以直接修改副本,如下所示:

var newOrders = state.slice();
var oldOrder = newOrders[action.orderIndex];
// make a shallow copy
var newOrder = Object.assign({}, oldOrder);
// we can now modify immediate properties of the copy
newOrder.quantity++;
newOrders[action.orderIndex] = newOrder;
return newOrders;
Run Code Online (Sandbox Code Playgroud)

两种处理方式之间的区别在于使用的版本map(以及更多ES6重型版本)是单个表达式.这使它更具功能性.而不是指定获取结果的步骤,而是指定结果应该是什么样子.这是声明与命令.

声明性版本有时更清晰.然后,通常它不是.这通常较短,但似乎非常陌生的.如果你来自功能世界,它的外观和感觉完全正常.外星人从不认为自己是外星人.

我建议易于理解比短代码更重要.请注意,它不可能更快.map例如,该版本为每个订单调用您的函数.

如果你有几百万个订单(我们都希望我们能得到),我们最终会检查每个订单,看看它是否是我们想要修改的订单.

但是,在使用命令式版本时,您会复制一个数组,在此期间我们不会检查任何订单.它比map版本快得多,速度也快得多.

那么为什么我们看到人们使用map呢?好吧,如果你只有几个订单,性能是没有问题的,那对于那里的功能纯粹主义者来说看起来很好.

还有Mark对ES6做事方式的回答.它通过在要替换的项目之前复制零件,添加新项目,然后在要替换的项目之后添加零件来创建新阵列.这很快.它也很丑陋(在我看来).

当然,如果你仔细想想它会发生什么.它取代了我们需要改变的一个项目.但是,它不像一个替代品.事实上,索引没有提到的唯一项目就是我们要替换的项目.

我想说,除非你试图证明你的整个应用程序只能是一个单独的表达式,否则编写命令式代码是完全可以的.如果它更容易理解或写,那么没有理由不这样做.