NGRX - 无法按照我的意愿设置状态树

时间:2018-03-30 21:05:00

标签: arrays typescript ngrx ngrx-store

所以我使用ngrx来管理我的应用程序中的状态。我试图添加一个新属性(选定的班次),它应该是这样的:

state: {
    shifts: {
        selectedShifts: [
            [employeeId]: [
                [shiftId]: shift
            ]
        ]
    }
}

此刻,我的州看起来像这样:

state: {
    selectedShifts: {
        [employeeId]: {
            [shiftId]: shift
        }
    }
}

所以你可以看到,我的选择班次"是一个属性,而不是一个数组 - 这使得难以添加/删除/查询状态。

如何将状态组合成我想要的状态?

这是我在reducer中尝试过的:

return {
    ...state,
    selectedShifts: {
      ...state.selectedShifts,
      [action.payload.employeeId]: {
        ...state.selectedShifts[action.payload.employeeId],
        [action.payload.shiftId]: action.payload[shift.shiftId]
      }
    }
  };

现在,当我试图按照我想要的方式返回状态时,结果就是这样:

state: {
    selectedShifts: {
        [action.payload.employeeId]: 
            [0]: {[action.payload.shiftId]: { shift }}
    }
}

我在这里缺少什么?当我尝试替换应该是[]的{}项时,会出现此错误:","预期

哦,是的,我希望数组的索引是特定班次的id而不是[0],[1] ......

这有可能吗? 将指数从数字改为实际转移的ID是不是一个坏主意?

1 个答案:

答案 0 :(得分:0)

在数字索引点添加数据时,数组长度类型的行为会出现。这可能会让您使用长度连接,切片,indexOf等数组方法遇到问题。数组方法改变长度推,拼接等

var fruits = [];
fruits.push('banana', 'apple', 'peach');

console.log(fruits.length); // 3

当属性是有效的数组索引并且该索引超出数组的当前边界时,在JavaScript数组上设置属性时,引擎将相应地更新数组的length属性:

fruits[5] = 'mango';
console.log(fruits[5]); // 'mango'
console.log(Object.keys(fruits));  // ['0', '1', '2', '5']
console.log(fruits.length); // 6

从对象中选择/更新状态没有问题,它与您可能习惯的状态略有不同。使用直接hashmap {objectId:Object},如果为对象id定义了更改,则找到更新/删除所需的对象是最快的。

我知道你的问题与NGRX有关,但是读取Redux不可变模式肯定会帮助你在这里添加/更新/从状态中删除对象。 https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns

一般情况下,您不希望状态中的数组(至少是大型数组)对象哈希映射要好得多。

要让所选用户的数组转换为视图,您可以执行类似的操作。请注意,这不是移位索引数组,只是userId属性下的移位数组。从原状态下面的状态。

state: {
    selectedShifts: {
        [employeeId]: {
            [shiftId]: shift
        }
    }
}
const getSelectedShiftsAsArray = this.store.select( getSelectedShifts() )
.map(
    userShifts => {
        // get array of object ids
        const userIds = Object.keys( userShifts );

        const ret = {};

        for( const userId of userIds ) { 
            const collectedShifts = [];
            // convert Dictionary<Shift> into a Shift[]
            // get array of shift ids
            const shiftIds = Object.keys( userShifts[userId] );
            // map array of shift ids into shift object array
            collectedShifts = shiftIds.map( shiftId => userShifts[shiftId] );
            // return value for a userId
            ret[userId] = collectedShifts;

        }

        return ret;
});

代码完全未经测试,仅用于伪代码的一级参考。您可以轻松地将其转换为NGRX选择器。状态只是存储,你如何建模它用于组件是选择器功能和&amp;组件本身。

如果你真的需要它,你可以添加。

ret[userId].shiftIds = shiftIds;
ret[userId].shifts = collectedShifts;

但这实际上取决于你打算如何使用它们。

根据我的个人经验,我会将shift实体与selectedShifts分开,但是你如何组织你的状态完全取决于你。

state: {
    shifts: {
        // contains shift entities as object property map id: entity
        entities: Dictionary<Shift>,
        selectedShifts: [
            [employeeId]: number[] // contains ids for shifts
        ]
    }
}

现在更新/删除和添加班次只是将更新的数据设置为路径shift.entities [entityId]

另外,为employeeId选择的提升将是检查id是否已经存在并将其附加到数组中(如果它不是)。 (如果这些数组非常庞大,我也可以使用对象哈希来快速访问。<employeeId>: {shiftId:shiftId})。

检查: redux: state as array of objects vs object keyed by id