Platform: Injecting meta-reducers

Created on 22 Aug 2017  路  8Comments  路  Source: ngrx/platform

As per the documentation, root reducers can be injected using an InjectionToken and a Provider to register the reducers through dependency injection.

Being able to do the same thing for meta-reducers is useful, as those often have side-effects like sending errors to a monitoring service, synchronizing state with sessionStorage.., which would benefit from Angular's DI framework.

This was apparently possible before v4 (https://github.com/ngrx/store/issues/313), but I couldn't find a way to do it now that the store handles the reducers composition. Is there a way to do that? Or could StoreConfig accept an InjectionToken<ActionReducer<T, V>>[] similarly to the forRoot's reducers param and inject the meta-reducers?

Most helpful comment

I agree with @samueledirito. I need the ability to inject services into MetaReducers that are specified using .forFeature(...). Can this please be re-opened, or should we file another bug?

Thanks!

All 8 comments

Injection tokens for meta reducers already exist in the API. If you need lower level access to managing reducers, you should use the ReducerManager, as its what's used underneath to add/remove/replace reducers.

Thanks @brandonroberts, I may have missed something but StoreModule.forRoot() only takes a StoreConfigobject

export class StoreModule {
  static forRoot<T, V extends Action = Action>(
    reducers: ActionReducerMap<T, V> | InjectionToken<ActionReducerMap<T, V>>,
    config?: StoreConfig<T, V>
  ): ModuleWithProviders;

whose type is

export type StoreConfig<T, V extends Action = Action> = {
  initialState?: InitialState<T>;
  reducerFactory?: ActionReducerFactory<T, V>;
  metaReducers?: MetaReducer<T, V>[];
};

Obviously TypeScript then complains that InjectionToken<MetaReducer<T, V>> isn't the same thing as MetaReducer<T, V>, although it won't work anyway since only INITIAL_REDUCERS and FEATURE_REDUCERS use injector.get().

And the ReducerManager addFeature & addReducer APIs would scope the reducer to a specific key / feature, so can't be used for meta reducers:

 addReducer(key: string, reducer: ActionReducer<any, any>) {
    this.reducers = { ...this.reducers, [key]: reducer };

    this.updateReducers();
  }

What's the proper way to achieve that? I've managed to make it work by manually composing my reducers using compose, it only feels weird that my code is taking care of reducer composition but I guess that's fine.

export function getReducers(errorHandler: ErrorHandler) {
  return compose.apply(null, [
        tryCatchReducerFactory(errorHandler),
  ])(reducers);
}

What's the proper way to achieve that? I've managed to make it work by manually composing my reducers using compose, it only feels weird that my code is taking care of reducer composition but I guess that's fine.

Actually that doesn't work since when using an InjectionToken StoreModule.forRoot still expect an reducers map, and not an already composed root reducer, so manual reducer composition can't do the trick. Am I missing something?

@laurentgoudet I was referring to the META_REDUCERS token for register meta reducers in the root.

import { META_REDUCERS } '@ngrx/store';
import { SomeService } from './some.service';

export function getMetaReducers(some: SomeService): MetaReducer[] {
  // return array of meta reducers;
}

@NgModule({
  providers: [
    {
      provide: META_REDUCERS,
      deps: [SomeService],
      useFactory: getMetaReducers
    }
  ]
})
export class AppModule {}

Thanks for getting back to me, after re-reading it this was exactly what you said in your initial reply, and it indeed works perfectly. I need more coffee :).

馃槃

@brandonroberts I'm sorry to reopen the conversation, but am I able to have the same behaviour on features modules?
My metareducer is related to the feature I'm developing, so it's totally useless to me to have its registration in root module.

TIA

I agree with @samueledirito. I need the ability to inject services into MetaReducers that are specified using .forFeature(...). Can this please be re-opened, or should we file another bug?

Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dmytro-gokun picture dmytro-gokun  路  3Comments

brandonroberts picture brandonroberts  路  3Comments

gperdomor picture gperdomor  路  3Comments

NathanWalker picture NathanWalker  路  3Comments

brandonroberts picture brandonroberts  路  3Comments