简体   繁体   中英

Which to use StoreModule.forRoot or StoreModule.forFeature?

I was reading about and they said that.forRoot merges all the reducers, and when manipulating the state in this way you are manipulating all the reducers at once.

Soon.forFeature allows you to manipulate each reducer as if it had a state for each one.

And I would like to know the following:

1) Is this true?

2) How to use .forFeature() with multiple reducers?

I'm getting the following error:

NullInjectorError: R3InjectorError(AppModule)[StoreFeatureModule -> ReducerManager -> ReducerManager -> ReducerManager]: 
  NullInjectorError: No provider for ReducerManager!

MODULE

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { environment } from 'environments/environment';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { STORE_REDUCERS, STORE_EFFECTS } from './store';

import { AppComponentModule } from '@app/components/app-component.module';
import { AppComponent } from './app.component';

@NgModule({
    declarations: [AppComponent],
    imports: [
        BrowserModule,
        AppComponentModule,
        HttpClientModule,
        StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: !environment.production }),
        StoreModule.forFeature('people', STORE_REDUCERS),
        EffectsModule.forFeature(STORE_EFFECTS),
    ],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

PEOPLE SELECTOR

import { createFeatureSelector, createSelector } from '@ngrx/store';
import { State, adapter } from './people.reducer';

const featureSelector = createFeatureSelector<State>('people');

export const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors(featureSelector);

export const getLoading = createSelector(featureSelector, ({ loading }) => loading);
export const getError = createSelector(featureSelector, ({ error }) => error);
export const getMain = createSelector(selectAll, (peoples) => peoples.filter((people) => people.isMain)[0]);

STORE INDEX:

import { ActionReducerMap } from '@ngrx/store';
import * as fromPeopleReducer from './people/people.reducer';
import * as fromPeopleEffects from './people/people.effects';

export interface StoreState {
    people: fromPeopleReducer.State;
}

export const STORE_REDUCERS: ActionReducerMap<StoreState> = {
    people: fromPeopleReducer.reducer,
};

export const STORE_EFFECTS: any[] = [fromPeopleEffects.Effects];

.forFeature isn't a replacement for .forRoot , it's a way how to inject reducers and effects into the global store from lazy loaded modules or from imported libraries.

in the AppModule or in your root module you have to have at least

imports: [
  StoreModule.forRoot({}),
  EffectsModule.forRoot([]),
],

and then in any other imported module you can add something like

imports: [
  StoreModule.forFeature('addresses', reducers.addresses),
  StoreModule.forFeature('companies', reducers.companies),
  StoreModule.forFeature('users', reducers.users),
  EffectsModule.forFeature([EntityEffects]),
],

It means that addresses , companies , users features will be added to the global store. if you do it in several modules it still will use the same feature name, it doesn't create a store context per module. Reducers will be receiving all available actions in the app and effects too.

I would recommend to use .forFeature if you write a package with a library for ngrx or if its reducer / effect is useless without this module and its components.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM