如何在 Redux reducer 中以不可变的方式交换数组元素?
How do I swap array elements in an immutable fashion within a Redux reducer?
相关的 Redux 状态由表示层的对象数组组成。
示例:
let state = [
{ id: 1 }, { id: 2 }, { id: 3 }
]
我有一个名为 moveLayerIndex 的 Redux 操作:
actions.js
export const moveLayerIndex = (id, destinationIndex) => ({
type: MOVE_LAYER_INDEX,
id,
destinationIndex
})
我希望 reducer 通过交换数组中元素的位置来处理操作。
reducers/layers.js
const layers = (state=[], action) => {
switch(action.type) {
case 'MOVE_LAYER_INDEX':
/* 我应该在这里放什么才能使下面的测试通过 */
default:
return state
}
}
测试验证 Redux reducer 以不可变的方式交换数组的元素。
Deep-freeze 用于检查初始状态未发生任何变异。
如何通过这个测试?
test/reducers/index.js
import { expect } from 'chai'
import deepFreeze from'deep-freeze'
const id=1
const destinationIndex=1
it('move position of layer', () => {
const action = actions.moveLayerIndex(id, destinationIndex)
const initialState = [
{
id: 1
},
{
id: 2
},
{
id: 3
}
]
const expectedState = [
{
id: 2
},
{
id: 1
},
{
id: 3
}
]
deepFreeze(initialState)
expect(layers(initialState, action)).to.eql(expectedState)
})
不可变更新的一个关键思想是,虽然您应该永远不要直接修改原始项目,但制作副本并改变副本是可以的在归还之前。
考虑到这一点,这个函数应该做你想做的事:
function immutablySwapItems(items, firstIndex, secondIndex) {
// Constant reference - we can still modify the array itself
const results= items.slice();
const firstItem = items[firstIndex];
results[firstIndex] = items[secondIndex];
results[secondIndex] = firstItem;
return results;
}
我为 Redux 文档编写了一个名为 Structuring Reducers - Immutable Update Patterns 的部分,其中提供了更新数据的一些相关方法的示例。
您可以使用 map 函数进行交换:
function immutablySwapItems(items, firstIndex, secondIndex) {
return items.map(function(element, index) {
if (index === firstIndex) return items[secondIndex];
else if (index === secondIndex) return items[firstIndex];
else return element;
}
}
ES2015 风格:
const immutablySwapItems = (items, firstIndex, secondIndex) =>
items.map(
(element, index) =>
index === firstIndex
? items[secondIndex]
: index === secondIndex
? items[firstIndex]
: element
)
其他两个答案都没有问题,但我认为用 ES6 有更简单的方法。
const state = [{
id: 1
}, {
id: 2
}, {
id: 3
}];
const immutableSwap = (items, firstIndex, secondIndex) => {
const result = [...items];
[result[firstIndex], result[secondIndex]] = [result[secondIndex], result[firstIndex]];
return result;
}
const swapped = immutableSwap(state, 2, 0);
console.log("Swapped:", swapped);
console.log("Original:", state);
相关的 Redux 状态由表示层的对象数组组成。
示例:
let state = [
{ id: 1 }, { id: 2 }, { id: 3 }
]
我有一个名为 moveLayerIndex 的 Redux 操作:
actions.js
export const moveLayerIndex = (id, destinationIndex) => ({
type: MOVE_LAYER_INDEX,
id,
destinationIndex
})
我希望 reducer 通过交换数组中元素的位置来处理操作。
reducers/layers.js
const layers = (state=[], action) => {
switch(action.type) {
case 'MOVE_LAYER_INDEX':
/* 我应该在这里放什么才能使下面的测试通过 */
default:
return state
}
}
测试验证 Redux reducer 以不可变的方式交换数组的元素。
Deep-freeze 用于检查初始状态未发生任何变异。
如何通过这个测试?
test/reducers/index.js
import { expect } from 'chai'
import deepFreeze from'deep-freeze'
const id=1
const destinationIndex=1
it('move position of layer', () => {
const action = actions.moveLayerIndex(id, destinationIndex)
const initialState = [
{
id: 1
},
{
id: 2
},
{
id: 3
}
]
const expectedState = [
{
id: 2
},
{
id: 1
},
{
id: 3
}
]
deepFreeze(initialState)
expect(layers(initialState, action)).to.eql(expectedState)
})
不可变更新的一个关键思想是,虽然您应该永远不要直接修改原始项目,但制作副本并改变副本是可以的在归还之前。
考虑到这一点,这个函数应该做你想做的事:
function immutablySwapItems(items, firstIndex, secondIndex) {
// Constant reference - we can still modify the array itself
const results= items.slice();
const firstItem = items[firstIndex];
results[firstIndex] = items[secondIndex];
results[secondIndex] = firstItem;
return results;
}
我为 Redux 文档编写了一个名为 Structuring Reducers - Immutable Update Patterns 的部分,其中提供了更新数据的一些相关方法的示例。
您可以使用 map 函数进行交换:
function immutablySwapItems(items, firstIndex, secondIndex) {
return items.map(function(element, index) {
if (index === firstIndex) return items[secondIndex];
else if (index === secondIndex) return items[firstIndex];
else return element;
}
}
ES2015 风格:
const immutablySwapItems = (items, firstIndex, secondIndex) =>
items.map(
(element, index) =>
index === firstIndex
? items[secondIndex]
: index === secondIndex
? items[firstIndex]
: element
)
其他两个答案都没有问题,但我认为用 ES6 有更简单的方法。
const state = [{
id: 1
}, {
id: 2
}, {
id: 3
}];
const immutableSwap = (items, firstIndex, secondIndex) => {
const result = [...items];
[result[firstIndex], result[secondIndex]] = [result[secondIndex], result[firstIndex]];
return result;
}
const swapped = immutableSwap(state, 2, 0);
console.log("Swapped:", swapped);
console.log("Original:", state);