鉴于这样的不可变状态:
alerts: {
5a8c76171bbb57b2950000c4: [
{
_id:5af7c8652552070000000064
device_id:5a8c76171bbb57b2950000c4
count: 1
},
{
_id:5af7c8722552070000000068
device_id:5a8c76171bbb57b2950000c4
count: 2
}
]
}
和这样的对象:
{
_id:5af7c8652552070000000064
device_id:5a8c76171bbb57b2950000c4
count: 2
}
我想在警报状态(不可变)中替换具有相同id的对象,这样最终结果如下所示:
alerts: {
5a12356ws13tch: [
{
_id:5af7c8652552070000000064
device_id:5a8c76171bbb57b2950000c4
count: 2
},
{
_id:5af7c8722552070000000068
device_id:5a8c76171bbb57b2950000c4
count: 2
}
]
}
我该怎么做?使用在List,Map或OrderedMap上找到的mergeDeep,getIn,setIn和updateIn?
我尝试过这样的事情......其中index为0,deviceId为5a12356ws13tch
虽然不起作用。
export const oneAlertFetched = (state, {deviceId, index, alert}) => state.setIn(['alerts', deviceId, index], alert).merge({fetching: false})
我也试过这个。不起作用。
export const oneAlertFetched = (state, {deviceId, index, alert}) => {
const a = state.alerts[deviceId][index]
state.alerts[deviceId][index] = Object.assign({}, a, alert)
return
}
答案 0 :(得分:1)
根据不可变,您的意思是您的财产不可写。
如果您想就地修改对象(不推荐),则需要该属性至少可配置:
const device = alerts['5a12356ws13tch'][0];
if (Object.getOwnPropertyDescriptor(device, 'count').configurable) {
// Manually make it `writable`
Object.defineProperty(device, 'count', {
writable: true
});
// Update property's value
device.count++;
// Set it back to `non-writable`
Object.defineProperty(device, 'count', {
writable: false
});
}
console.log(device.count); // 2
如果它不可配置(不能使其可写),或者您不想破坏您的应用程序(它必须是故意不可写的),那么您应该处理副本。
const device = alerts['5a12356ws13tch'][0];
alerts['5a12356ws13tch'][0] = Object.assign({}, device, {count: device.count + 1});
Object.assign()
适用于扁平物体。如果您需要深层复制,请查看my SO answer there。
答案 1 :(得分:0)
我认为你的意思是你想要使用更新的有效负载返回一个新对象?
function getNextAlerts(alerts, parentDeviceId, payload) {
const alertsForDevice = alerts[parentDeviceId];
if (!alertsForDevice || alertsForDevice.length === 0) {
console.log('No alerts for device', deviceId);
return;
}
return {
...alerts,
[parentDeviceId]: alerts[parentDeviceId].map(item =>
item._id === payload._id ? payload : item
),
}
}
const alerts = {
'5a12356ws13tch': [
{
_id: '5af7c8652552070000000064',
device_id: '5a8c76171bbb57b2950000c4',
count: 1
},
{
_id: '5af7c8722552070000000068',
device_id: '5a8c76171bbb57b2950000c4',
count: 2
}
]
};
const nextAlerts = getNextAlerts(alerts, '5a12356ws13tch', {
_id: '5af7c8652552070000000064',
device_id: '5a8c76171bbb57b2950000c4',
count: 2,
});
console.log('nextAlerts:', nextAlerts);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
答案 2 :(得分:0)
如果您正在使用纯JavaScript对象并希望保持&#34; immutable&#34;方法你必须在状态对象的嵌套结构中使用遍布。
但是,有一些工具已经针对这个问题 - 镜头。
这是两种方法的示例,阵列/对象传播和镜头 - ramda repl。
简而言之,您的例子是通过点差:
const oneAlertFetched = (state, { deviceId, index, alert }) => ({
...state,
alerts: {
...state.alerts,
[deviceId]: [
...state.alerts[deviceId].slice(0, index),
{ ...state.alerts[deviceId][index], ...alert },
...state.alerts[deviceId].slice(index + 1)
],
}
})
使用Ramda&#39; over, lensPath, merge and __
*:
const oneAlertFetched = (state, { deviceId, index, alert }) =>
R.over(
R.lensPath(['alerts', deviceId, index]),
R.merge(R.__, alert),
state
)
* R.__
占位符用于交换1st&amp; R.merge
PS:有意调整镜头解决方案以匹配您的功能声明,因此您可以轻松比较两种方法。然而,在现实生活中,借助如此强大而灵活的工具,我们可以将该功能重写为更具可读性,可重用性和高性能。