Angular ngrx-store: как разделить хранилище между модулями (основной модуль / функциональный модуль)

У меня есть два угловых модуля: main и feature:

Основной/корневой модуль:

@NgModule({
    imports: [
        StoreModule.forRoot({router: routerReducer}),
        EffectsModule.forRoot([...]),
        ...
    ],
    declarations: [],
    ...
})
export class AppModule {}

Функциональный модуль:

@NgModule({
    imports: [
        StoreModule.forFeature('feature', {someValue: someValueReducer}),
        EffectsModule.forFeature([...]),
        ...
    ],
    declarations: [],
    ...
})
export class FeatureModule {}

Мне нужно получить доступ к фрагменту данных "feature" в основном модуле, чтобы условно отобразить/активировать вкладку приложения на основе данных, хранящихся в feature модуле.

(Другими словами, мне нужна глобальная/общая часть состояния, доступная всем модулям main и любому модулю feature.)

  1. Возможно ли это сделать?
  2. Считается ли это хорошей практикой?

В настоящее время я не могу этого сделать, так как в основном AppState нет состояния feature:

export interface AppState {
    router: RouterReducerState<RouterStateUrl>;
}

А машинопись указывает на ошибку this.store.select('feature'), так как нет ключа feature основного хранилища AppState.

Используя selector: this.store.select(selectFeatureValue) я получаю ошибку времени выполнения:

export const selectFeatureModule = createFeatureSelector<FeatureState>('feature');
export const selectFeatureValue = createSelector(selectFeatureModule ,
(state: FeatureState) => state.someValue);

Я получаю сообщение об ошибке в основном AppComponent:

TypeError: Невозможно прочитать свойство «someValue» неопределенного


person Felix    schedule 31.10.2017    source источник
comment
setTimeout(() => this.store.select(selectFeatureValue) .subscribe(console.log.bind(console)), 1000); избавит от ошибки времени выполнения, но я бы предпочел избавиться от setTimeout   -  person Felix    schedule 31.10.2017


Ответы (3)


На мой взгляд, это в значительной степени противоречит цели как ленивой загрузки модулей, так и ленивой загрузки хранилищ.

Вероятно, вам следует пересмотреть свой дизайн. Обычно наоборот, вам нужно основное состояние в вашем функциональном модуле, и это нормально, поскольку вы не можете активировать функциональный модуль без основного, но наоборот немного странно.

Теперь, как говорится, основная идея хранилища с отложенной загрузкой заключается в том, что у вас нет ключей хранилища функций в вашем основном хранилище, но они добавляются позже, в течение срока службы приложения по мере необходимости. Итак, что вы можете сделать, так это импортировать свой редуктор функций в компонент основного модуля, где он вам нужен, и напрямую выбирать из редуктора функций. Но опять же, это вопрос, если это то, что кто-то хотел бы сделать. Я бы не стал.

Я бы переосмыслил дизайн и вещи, которые мне нужны в основном модуле, которые я бы поместил в основной редуктор/хранилище.

person dee zg    schedule 31.10.2017
comment
Спасибо за ответ. Принимая во внимание обратное — функциональный модуль имеет доступ к основному хранилищу модулей, каким будет синтаксис для доступа к срезу основного хранилища из функционального модуля, учитывая, что функциональный модуль имеет свой собственный тип FeatureState? - person Felix; 31.10.2017
comment
Я мог бы отправить действие в основном модуле, а редуктор хранилища функций мог бы получить/обработать это действие и использовать полезную нагрузку для сохранения своей собственной копии (аналогично редуктору основного хранилища). - person Felix; 31.10.2017
comment
метаредукторы - это то, что вы, возможно, ищете. например: netbasal.com/ - person dee zg; 31.10.2017
comment
Подумав об этом еще раз: если основной модуль имеет зависимость (модуль) от функционального модуля, я не могу поделиться состоянием в основном модуле - в этом случае функциональный модуль также должен иметь зависимость (модуль) от основного модуля. создание циклической зависимости. - person Felix; 17.01.2018
comment
если ваш основной модуль зависит от функционального модуля, то ваш функциональный модуль не является лениво загруженным. хотя это не обязательно связано с ленивой загрузкой частей хранилища. но в целом вы хотите, чтобы редукторы с ленивой загрузкой следовали за лениво загруженными модулями, чтобы у вас не было циклических зависимостей. - person dee zg; 19.01.2018
comment
Разве это не то, что делает пример приложения ngrx? Компонент контейнера на github.com/ ngrx/platform/blob/master/example-app/app/core/ из core.module обращается к authState из другого функционального модуля, auth.module. Это случай совместного использования состояния между двумя функциональными модулями, но я не думаю, что он сильно отличается от исходного вопроса в этой ветке. Является ли этот аспект примера приложения примером плохого дизайна, который вы описываете? Не собираюсь обсуждать хороший/плохой дизайн, просто пытаюсь понять ваш совет и образец приложения. - person Eric Bowden; 12.02.2018
comment
Обычно наоборот, вам нужно основное состояние в вашем функциональном модуле, и это нормально, нет. Тем самым вы нарушаете принцип инверсии зависимостей. - person Tom; 22.06.2020
comment
@Том, ты уверен? можешь уточнить? например, если вы сохраняете зарегистрированного пользователя или некоторые настройки приложения в основном состоянии, почему использование этой информации в функциональных модулях нарушает принцип инверсии управления? - person dee zg; 24.06.2020
comment
@deezg Теперь ваш функциональный модуль знает об основном состоянии. Что, если вы используете этот модуль в другом приложении? Теперь ваш функциональный модуль зависит от основного состояния и основного состояния функционального модуля... - person Tom; 24.06.2020
comment
@ Том, я не уверен, что это правильно. может быть, вы могли бы начать с цитирования принципа инверсии зависимостей и указать на его часть, которая нарушена? / я никогда не говорил, что основной модуль зависит от функционального модуля; это ясная проблема. я сказал, что функциональный модуль зависит от основного (при необходимости). не идеально, но тем не менее я не вижу нарушения принципа инверсии зависимостей. - person dee zg; 30.06.2020
comment
@deezg Верно как раз обратное. Основные модули должны зависеть от функциональных модулей. Функциональные модули не должны зависеть от основного модуля. Представьте, что вы хотите использовать функциональные модули в другом приложении. Вы не можете, если вы также не обновите другое, новое приложение, чтобы оно имело то же состояние, что и предыдущее приложение. - person Tom; 30.06.2020
comment
@ Том, не могли бы вы процитировать принцип инверсии зависимостей, в котором говорится об этом? - person dee zg; 30.06.2020

Я думаю, что это правильный вопрос, по крайней мере частично. Представьте себе следующую структуру:

appState
├── coreState
│
├── lazyModuleSate1
│   ├── subStateA
│   └── subStateB
│
└── lazyModuleSate2
    ├── subStateA
    └── subStateB
  • coreState может содержать общую информацию о пользователе, сеансе...

  • Редукторам ленивых модулей может потребоваться доступ к такому общему состоянию при обработке действий.

    НО

  • Редукторы основного модуля видят только coreState.

  • Редукторы ленивых модулей (определенные с помощью ActionReducerMap) видят только свое собственное подсостояние. В большинстве случаев это красиво и чисто, но иногда действия должны обрабатываться при условии coreState. Не было бы проблем, coreState всегда в магазине.

  • Метаредьюсеры, определенные в ленивых модулях, видят ТОЛЬКО свой собственный lazyModuleState. По-прежнему полезно обрабатывать взаимосвязи между подсостояниями, но они не помогают с отношениями coreState - lazyModuleSate.

  • Только глобальные метаредукторы, определенные на уровне приложения, видят coreState. Здесь можно обрабатывать действия, хотя и очень некрасиво.

person bdi    schedule 22.12.2018

Мое решение:

  • извлечен дополнительный функциональный модуль под названием core. Я преобразовал все общие глобальные данные/состояния, необходимые для других модулей, в ядро.
  • добавлена ​​зависимость от всех модулей, использующих общее состояние на ядре (без круговой зависимости)
  • используя селекторы из модуля core, нет проблем с машинописным текстом, указывающим, что такого ключа нет в хранилище
person Felix    schedule 17.01.2018