Я получаю TypeErrors при использовании функций выбора NgRx при доступе к вложенным свойствам.
У меня root мое хранилище сконфигурировано в app.module.ts
, например:
StoreModule.forRoot({ app: appReducer }),
где приложение Редуктор это просто стандартный редуктор. Он правильно устанавливает состояние; Я могу видеть это в инструментах редукционного разработчика. Селекторы для некоторых вложенных свойств, которые содержат ошибки:
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
, которые установлены в нуль. Я не думаю, что эта селекторная функция должна срабатывать, пока значение не изменится с первоначального значения. Но так как это не так, неудивительно, что я получаю эту ошибку, так как он пытается получить доступ к свойству с нулевым значением. Обязательно ли, чтобы initialState
содержал полное дерево всех потенциальных будущих вложенных свойств, чтобы не сломать мои селекторы?
Как можно предотвратить срабатывание этого селектора, если его значение не изменилось?
Кроме того, правильно ли настроен StoreModule.forRoot
? Меня несколько озадачивает тот факт, что при создании хранилища "root" создается ключ app
в моем хранилище резервных копий параллельно хранилищам моих модулей, ie, хранилища модулей не находятся под app
.
Редактировать:
Добавление общей структуры app.reducer.ts
. Я использую immer , чтобы сократить шаблон, необходимый для обновления вложенных свойств, однако я попробовал этот редуктор также как более традиционный тип с оператором распространения по всему месту, и он работает идентично.
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,
}
},
},
};