【发布时间】:2020-07-10 08:21:41
【问题描述】:
在访问嵌套属性时使用 NgRx 选择函数时出现 TypeErrors。
我在app.module.ts 中配置了我的根存储,如下所示:
StoreModule.forRoot({ app: appReducer }),
app reducer 只是一个标准的 reducer。它正确地设置了状态;我可以在 redux 开发工具中看到这一点。一些出错的嵌套属性的选择器是:
const getAppFeatureState = createFeatureSelector<IAppState>('app');
export const getAppConfig = createSelector(getAppFeatureState, state => {
return state.appConfig.data;
});
export const getConfigControls = createSelector(getAppConfig, state => {
console.log({ state }) // logs values from initial state
return state.controls;
});
export const getConfigDropdowns = createSelector(
getConfigControls,
state => state.dropdowns,
);
当我像这样在app.compontent.ts 订阅这些选择器时
ngOnInit() {
this.store.dispatch(new appActions.LoadAppConfig());
this.store
.pipe(select(appSelectors.getConfigDropdowns))
.subscribe(data => {
console.log('OnInit Dropdowns Data: ', data);
});
}
app.component.ts:31 ERROR TypeError: Cannot read property 'dropdowns' of null at app.selectors.ts:18
当我将日志记录添加到链更高的选择器时,我可以看到唯一记录的元素是 initialState 值,它们设置为 null。我不认为这个选择器函数应该在值从它的初始值改变之前触发。但既然它没有,我得到这个错误也就不足为奇了,因为它试图访问 null 上的属性。 initialState 是否有必要包含所有潜在的未来嵌套属性的完整树,以免破坏我的选择器?
如何防止此选择器在其值不变时触发?
另外,StoreModule.forRoot 的配置是否正确?让我有些困惑的是,创建一个“根”存储,在我的 redux 存储中创建与我的模块存储平行的 app 键,即模块存储不在 app 之下。
编辑:
添加app.reducer.ts的通用结构。我使用immer 来缩短更新嵌套属性所需的样板文件,但是我也尝试过这个reducer 作为更传统的类型,它在整个地方都有传播运算符,它的工作原理是一样的。
import produce from 'immer';
export const appReducer = produce(
(
draftState: rootStateModels.IAppState = initialState,
action: AppActions,
) => {
switch (action.type) {
case AppActionTypes.LoadAppConfig: {
draftState.appConfig.meta.isLoading = true;
break;
}
/* more cases updating the properties accessed in problematic selectors */
default: {
return draftState; // I think this default block is unnecessary based on immer documentation
}
}
}
编辑:添加initialState:
const initialState: rootStateModels.IAppState = {
user: null,
appConfig: {
meta: {isError: false, isLoading: false, isSuccess: false},
data: {
controls: {
dropdowns: null,
}
},
},
};
【问题讨论】:
-
我认为问题在于您如何注册功能状态。您正在将状态注册为 root,但将其作为功能状态访问。将您的州注册为
StoreModule.forFeature- 参考 - ngrx.io/guide/store/reducers#register-feature-state -
@user2216584 我正在查看他们的
forRootdocumentation,我所拥有的似乎是正确的。我使用forFeature语法来注册单独的模块。 -
1) 请提供您的
initialState值。 2) 你不应该在你的 reducer 中改变draftState,而是返回一个新的{...draftState, ...}值。 3) 建议:存储中的深层嵌套对象可能很难管理。 -
@ThierryFalvo 我正在完全按照 immer 文档直接更新
draftState。有什么问题? -
@ThierryFalvo 我已经添加了
initialState
标签: javascript angular typescript rxjs ngrx