如何在Redux reducer中以不可变的方式交换数组元素?

the*_*ode 7 javascript arrays immutability redux

相关的Redux状态由表示层的对象数组组成.

例:

let state = [
    { id: 1 }, { id: 2 }, { id: 3 }
]
Run Code Online (Sandbox Code Playgroud)

我有一个名为moveLayerIndex的Redux动作:

actions.js

export const moveLayerIndex = (id, destinationIndex) => ({
    type: MOVE_LAYER_INDEX,
    id,
    destinationIndex
})
Run Code Online (Sandbox Code Playgroud)

我希望reducer通过交换数组中元素的位置来处理动作.

减速器/ layers.js

const layers = (state=[], action) => {
    switch(action.type) {
        case 'MOVE_LAYER_INDEX':
Run Code Online (Sandbox Code Playgroud)

/*我应该在这里做什么来做下面的测试通过*/

        default:
         return state
    }
}
Run Code Online (Sandbox Code Playgroud)

测试验证Redux reducer以不可变的方式交换数组的元素.

深度冻结用于检查初始状态是否以任何方式发生变异.

如何让这个测试通过?

测试/减速器/ 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)
 })
Run Code Online (Sandbox Code Playgroud)

mar*_*son 8

不可变更新的一个关键思想是,虽然你永远不应该直接修改原始项目,但是可以在复制之前制作副本并改变副本.

考虑到这一点,这个功能应该做你想要的:

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;
}
Run Code Online (Sandbox Code Playgroud)

我为Redux文档编写了一个名为Structuring Reducers - Immutable Update Patterns的部分,其中给出了一些更新数据的相关方法的示例.


Ger*_*dre 5

您可以使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在 ES2015 风格中:

const immutablySwapItems = (items, firstIndex, secondIndex) =>
  items.map(
    (element, index) =>
      index === firstIndex
        ? items[secondIndex]
        : index === secondIndex
        ? items[firstIndex]
        : element
  )
Run Code Online (Sandbox Code Playgroud)

  • 嗨@JohnBernardsson,感谢您的评论。当您说简单交换是常量而返回新数组是线性的时,您是对的。但是,如果检查这个问题,它是以不可变的方式进行的,这意味着不更改当前数组,而是返回一个新数组。几乎所有数组中的不可变操作都至少是线性的......查看此介绍以获取对不可变思想的简要说明:https://facebook.github.io/immutable-js/docs/#/ (2认同)