使用 redux 设置嵌套在不可变映射中的 属性 的值
Setting the value of a property nested in an Immutable map with redux
我正在尝试使用减速器设置 state.case.summaries.get(action.summary.id).metadata.summaryRank
的值。 summaries
是 Immutable.Map<string, Summary>;
我试过这个:
return {
...state,
'case' : {
...state.case,
summaries : {
...state.case.summaries,
[action.summary.id] : {
...state.case.summaries.get(action.summary.id),
metadata : {
...state.case.summaries.get(action.summary.id).metadata,
summaryRank : action.newRank
}
}
}
}
};
但我正在失去我的类型:
`state` before:
ApplicationState {_map: Map, __ownerID: undefined}
after:
{_map: Map, __ownerID: undefined, case: {…}}
`case` before:
Case {_map: Map, __ownerID: undefined}
after:
{_map: Map, __ownerID: undefined, summaries: {…}}
`summaries` before
Map {size: 44, _root: HashArrayMapNode, __ownerID: undefined, __hash: undefined, __altered: false}
after
{size: 44, _root: HashArrayMapNode, __ownerID: undefined, __hash: undefined, __altered: false, …}
所以如果我稍后尝试做 summaries.get(summaryId)
,我最终会得到 applicationState.case.summaries.get is not a function
然后我尝试这样做:
return state.set('case',
state.case.set('summaries',
state.case.summaries.get(action.summary.id).set(//not sure what to do here
state.case.summaries.get(action.summary.id).set('metadata',
state.case.summaries.get(action.summary.id).metadata.set('summaryRank',
action.newRank
)
)
)
)
);
但我得到:
[exec]
[exec] 46 state.case.summaries.get(action.summary.id).set(
[exec] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[exec] 47 state.case.summaries.get(action.summary.id).set('metadata',
[exec] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[exec] ...
[exec] 51 )
[exec] ~~~~~~~~~~~~~~~~~~~~~~~~~
[exec] 52 )
[exec] ~~~~~~~~~~~~~~~~~~~~~
[exec]
[exec] .../services/store/caseReducer.ts(46,21): error TS2346: Supplied parameters do not match any signature of call target.
[exec]
更多信息
case.ts
const CaseRecord = Immutable.Record({
id: '',
reserved:false,
loaded: false,
summaries: Immutable.Map<string, Summary>(),
caseMetadata: new models.CaseMetadata(),
});
export class Case extends CaseRecord {
public id: string;
public loaded: boolean;
public reserved: boolean;
public summaries: Immutable.Map<string, Summary>;
public caseMetadata: models.CaseMetadata;
constructor(properties?: any) {
super(properties);
}
public asMutable(): Case {
let record = <Case>super.asMutable();
record.summaries = this.summaries.asMutable();
this.summaries.forEach((summary) => {
record.summaries = record.summaries.set(summary.id, <models.Summary>summary.asMutable());
});
record.caseMetadata = this.caseMetadata.asMutable();
return record;
}
}
applicationState.ts
const ApplicationStateRecord = Immutable.Record({
case: new models.Case(),
lookupValues: {}
});
export class ApplicationState extends ApplicationStateRecord {
public case: models.Case;
public lookupValues: LookupValues;
constructor(properties?: any) {
super(properties);
}
}
在你的 redux store 中小心使用 class 类型——你必须确保你没有使用普通的 JS 对象。
当您执行以下操作时:
return { /* stuff */ }
redux 无法判断您是从另一种类型派生的。您可以应用原始原型执行以下操作:
return Object.assign(new ApplicationState(), { /* stuff */ })
但是,当嵌套很多时,它会非常乏味。
谢天谢地,您似乎一直在使用不可变的东西,这使得更新嵌套类型变得相当容易。我相信你可以做到:
return state.setIn(
['case', 'summaries', action.summary.id, 'metadata', 'summaryRank'],
action.newRank
)
这将根据需要创建密钥,并根据需要使用 Immutable 的映射。
我正在尝试使用减速器设置 state.case.summaries.get(action.summary.id).metadata.summaryRank
的值。 summaries
是 Immutable.Map<string, Summary>;
我试过这个:
return {
...state,
'case' : {
...state.case,
summaries : {
...state.case.summaries,
[action.summary.id] : {
...state.case.summaries.get(action.summary.id),
metadata : {
...state.case.summaries.get(action.summary.id).metadata,
summaryRank : action.newRank
}
}
}
}
};
但我正在失去我的类型:
`state` before:
ApplicationState {_map: Map, __ownerID: undefined}
after:
{_map: Map, __ownerID: undefined, case: {…}}
`case` before:
Case {_map: Map, __ownerID: undefined}
after:
{_map: Map, __ownerID: undefined, summaries: {…}}
`summaries` before
Map {size: 44, _root: HashArrayMapNode, __ownerID: undefined, __hash: undefined, __altered: false}
after
{size: 44, _root: HashArrayMapNode, __ownerID: undefined, __hash: undefined, __altered: false, …}
所以如果我稍后尝试做 summaries.get(summaryId)
,我最终会得到 applicationState.case.summaries.get is not a function
然后我尝试这样做:
return state.set('case',
state.case.set('summaries',
state.case.summaries.get(action.summary.id).set(//not sure what to do here
state.case.summaries.get(action.summary.id).set('metadata',
state.case.summaries.get(action.summary.id).metadata.set('summaryRank',
action.newRank
)
)
)
)
);
但我得到:
[exec]
[exec] 46 state.case.summaries.get(action.summary.id).set(
[exec] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[exec] 47 state.case.summaries.get(action.summary.id).set('metadata',
[exec] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[exec] ...
[exec] 51 )
[exec] ~~~~~~~~~~~~~~~~~~~~~~~~~
[exec] 52 )
[exec] ~~~~~~~~~~~~~~~~~~~~~
[exec]
[exec] .../services/store/caseReducer.ts(46,21): error TS2346: Supplied parameters do not match any signature of call target.
[exec]
更多信息
case.ts
const CaseRecord = Immutable.Record({
id: '',
reserved:false,
loaded: false,
summaries: Immutable.Map<string, Summary>(),
caseMetadata: new models.CaseMetadata(),
});
export class Case extends CaseRecord {
public id: string;
public loaded: boolean;
public reserved: boolean;
public summaries: Immutable.Map<string, Summary>;
public caseMetadata: models.CaseMetadata;
constructor(properties?: any) {
super(properties);
}
public asMutable(): Case {
let record = <Case>super.asMutable();
record.summaries = this.summaries.asMutable();
this.summaries.forEach((summary) => {
record.summaries = record.summaries.set(summary.id, <models.Summary>summary.asMutable());
});
record.caseMetadata = this.caseMetadata.asMutable();
return record;
}
}
applicationState.ts
const ApplicationStateRecord = Immutable.Record({
case: new models.Case(),
lookupValues: {}
});
export class ApplicationState extends ApplicationStateRecord {
public case: models.Case;
public lookupValues: LookupValues;
constructor(properties?: any) {
super(properties);
}
}
在你的 redux store 中小心使用 class 类型——你必须确保你没有使用普通的 JS 对象。
当您执行以下操作时:
return { /* stuff */ }
redux 无法判断您是从另一种类型派生的。您可以应用原始原型执行以下操作:
return Object.assign(new ApplicationState(), { /* stuff */ })
但是,当嵌套很多时,它会非常乏味。
谢天谢地,您似乎一直在使用不可变的东西,这使得更新嵌套类型变得相当容易。我相信你可以做到:
return state.setIn(
['case', 'summaries', action.summary.id, 'metadata', 'summaryRank'],
action.newRank
)
这将根据需要创建密钥,并根据需要使用 Immutable 的映射。