@StoreChunk

Introduction

To benefit from @ngrx-ducks' dynamic facades, the respective class needs to be connected to NgRx Store. To do so, @ngrx-ducks/core provides the decorator @StoreChunk that solves two tasks for you:

  1. Connecting ducks and selectors with the store.

  2. Registering the Facade as service in Angular's IoC container.

import { StoreChunk } from '@ngrx-ducks/core';

@StoreChunk()
export class Chunk {}

If you use @StoreChunk you are not allowed to add a constructor taking any parameters. This is by design to keep the Chunk-Class side-effect-free.

Using the Chunk-Service in you component also means that Redux-Infrastructure does not bleed into you components anymore.

The component only speaks to a service providing streams and dispatching messages (aka. actions).

Automatic Store registration

TLDR

See Store registration in action at ⚡️StackBlitz.

What is it?

Since NgRx Ducks version 12.4 a Chunk can be automatically be registered in the NgRx Store.

The chapters createDuck, createMutableDuck, getReducer and getMutableReducer will teach you that a reducer function is generated out of the Facade class.

This Reducer function needs to be registered in the Store by using StoreModule.forRoot or StoreModule.forFeature.

@StoreChunk({
  feature: 'counter',
  defaults: { count: 0 }
})
export class Chunk {

Since Version 13 setting feature will cause NgRx Ducks to prefix every Action-Type for you.

Plain Reducer Registration

A feature can have one single reducer.

@StoreFacade accepts a configuration that specifies where the Facade's reducer is about to be registered in the Store.

import { StoreChunk } from '@ngrx-ducks/core';

  /* Example
   * add = createDuck('[Counter] Add', (state: Counter, payload: number) => {
   *   return {
   *     ...state,
   *     count = state.count + payload
   *  }
   * });
  /*
}

The configuration requires a key, where the reducer should be registered in the store. For that, you need to set feature. The property defaults (aka. Initial State) specifies the start value of the reducer.

The configuration shown above causes the state to have a feature counter with an initial count of 0.

{                 // state
  counter: {      // feature 
    count: 0      // defaults
  }
}

@StoreFacade produces a Tree-Shakable-Provider. That's why you need to inject the Facade somewhere to cause the State being initialised. If the Facade is not used anywhere in your project, the coresponding state is not available either.

Using @StoreFacade's configuration also means that you do not need to use StoreModule.forFeature(). Setting up the feature and the reducer is done for you, automatically. 🚀

Slice Registration

A feature can also have multiple reducers.

In NgRx you would need to set up an ActionReducerMap<T> to combine multiple reducers that belong to a feature. NgRx Ducks allows you to write a single line of code to configure that the reducer is a sibling next to other reducers of the feature.

export interface CounterFeatureState {
  simple: CounterState,
  complex: ConterComplexState
}

@StoreChunk<CounterFeatureState>({
  feature: 'counter',
  slice: 'simple',
  defaults 
})

The configuration shown above causes the state to have a feature counter that contains a slice called simple with an initial count of 0.

{                 // state
  counter: {      // feature 
    simple: {     // slice   
      count: 0    // defaults
    }
  }
}

Type safety

@StoreFacade can be typed as well to ensure that defaults are set up the correct way.

If you register a plain reducer for a feature, the type argument is responsible for checking the defaults.

const defaults: CounterState = { count: 0, isLoading: true };

@StoreChunk<CounterState>({ feature: 'counter', defaults })
export class CounterFacade {}

If you register a slice for a feature. The type argument will check if the key of the slice and the defaults are correct.

export interface CounterFeatureState {
  simple: CounterState,
  complex: ConterComplexState
}

@StoreChunk<CounterFeatureState>({
  feature: 'counter',
  slice: 'simple',
  defaults 
})

The following screenshot demonstrates the occurring compiler error if a slice-key is misspelled.

Last updated