CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ngrx--schematics

Angular CLI schematics for generating NgRx state management code including actions, reducers, effects, selectors, and feature modules.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

reducer-generation.mddocs/

Reducer Generation

NgRx reducer generation schematic that creates type-safe reducer functions using createReducer and on() functions to handle state updates in response to dispatched actions. Reducers are pure functions that specify how the application's state changes in response to actions.

Capabilities

Reducer Schematic

Generates NgRx reducer functions with proper state management and action handling.

# Basic reducer generation
ng generate @ngrx/schematics:reducer User

# Reducer with creator functions
ng generate @ngrx/schematics:reducer User --creators

# Feature reducer setup
ng generate @ngrx/schematics:reducer User --feature
/**
 * Reducer schematic configuration interface
 */
interface ReducerSchema {
  /** Name of the reducer (typically entity or feature name) */
  name: string;
  /** Path where reducer files should be generated */
  path?: string;
  /** Angular project to target */
  project?: string;
  /** Generate files without creating a folder */
  flat?: boolean;
  /** Group reducer files within folders */
  group?: boolean;
  /** Path to existing reducers file for feature setup */
  reducers?: string;
  /** Generate as feature reducer */
  feature?: boolean;
  /** Use creator functions (createReducer) */
  creators?: boolean;
}

Basic Reducer Generation

Creates reducer functions using NgRx's createReducer and on() functions with proper state typing.

// Generated reducer with state interface
import { createReducer, on } from '@ngrx/store';
import * as UserActions from './user.actions';

export interface UserState {
  users: User[];
  loading: boolean;
  error: string | null;
  selectedUserId: string | null;
}

export const initialState: UserState = {
  users: [],
  loading: false,
  error: null,
  selectedUserId: null
};

export const userReducer = createReducer(
  initialState,
  
  on(UserActions.loadUsers, (state) => ({
    ...state,
    loading: true,
    error: null
  })),
  
  on(UserActions.loadUsersSuccess, (state, { users }) => ({
    ...state,
    users,
    loading: false,
    error: null
  })),
  
  on(UserActions.loadUsersFailure, (state, { error }) => ({
    ...state,
    loading: false,
    error
  })),
  
  on(UserActions.selectUser, (state, { userId }) => ({
    ...state,
    selectedUserId: userId
  })),
  
  on(UserActions.clearUsers, (state) => ({
    ...state,
    users: [],
    selectedUserId: null
  }))
);

Usage Examples:

# Generate user reducer
ng generate @ngrx/schematics:reducer User --creators

# Generate product reducer with custom path
ng generate @ngrx/schematics:reducer Product --path=src/app/catalog --creators

State Interface Definition

The schematic generates comprehensive state interfaces with proper typing:

/**
 * Generated state interface with common patterns
 */
interface GeneratedState {
  /** Collection of entities */
  entities: Entity[];
  /** Loading state indicator */
  loading: boolean;
  /** Error message if any */
  error: string | null;
  /** Currently selected entity ID */
  selectedId: string | null;
  /** Additional filters or search criteria */
  filters?: FilterCriteria;
  /** Pagination information */
  pagination?: PaginationState;
}

interface PaginationState {
  page: number;
  pageSize: number;
  total: number;
}

interface FilterCriteria {
  searchTerm?: string;
  status?: string;
  dateRange?: DateRange;
}

Feature Reducer Integration

When using --feature flag, the schematic integrates with existing reducer files:

// Generated feature reducer integration
import { ActionReducerMap, MetaReducer } from '@ngrx/store';
import * as fromUser from './user.reducer';
import * as fromProduct from './product.reducer';

export interface AppState {
  user: fromUser.UserState;
  product: fromProduct.ProductState;
}

export const reducers: ActionReducerMap<AppState> = {
  user: fromUser.userReducer,
  product: fromProduct.productReducer
};

export const metaReducers: MetaReducer<AppState>[] = [];

Usage Examples:

# Add to existing feature reducers
ng generate @ngrx/schematics:reducer Order --feature --reducers=src/app/state/index.ts

# Create feature reducer with grouping
ng generate @ngrx/schematics:reducer Inventory --feature --group

Action Handler Patterns

The reducer includes common action handling patterns:

// CRUD operation handlers
export const entityReducer = createReducer(
  initialState,
  
  // Load operations
  on(EntityActions.loadEntities, (state) => ({
    ...state,
    loading: true,
    error: null
  })),
  
  on(EntityActions.loadEntitiesSuccess, (state, { entities }) => ({
    ...state,
    entities,
    loading: false
  })),
  
  on(EntityActions.loadEntitiesFailure, (state, { error }) => ({
    ...state,
    loading: false,
    error
  })),
  
  // Create operations
  on(EntityActions.createEntitySuccess, (state, { entity }) => ({
    ...state,
    entities: [...state.entities, entity]
  })),
  
  // Update operations
  on(EntityActions.updateEntitySuccess, (state, { entity }) => ({
    ...state,
    entities: state.entities.map(e => 
      e.id === entity.id ? entity : e
    )
  })),
  
  // Delete operations
  on(EntityActions.deleteEntitySuccess, (state, { id }) => ({
    ...state,
    entities: state.entities.filter(e => e.id !== id)
  })),
  
  // Selection operations
  on(EntityActions.selectEntity, (state, { id }) => ({
    ...state,
    selectedId: id
  })),
  
  on(EntityActions.clearSelection, (state) => ({
    ...state,
    selectedId: null
  }))
);

Immutable State Updates

The generated reducer ensures immutable state updates following NgRx best practices:

/**
 * Immutable state update patterns used in generated reducers
 */
interface StateUpdatePatterns {
  /** Replace array items */
  replaceInArray: <T>(array: T[], item: T, matcher: (item: T) => boolean) => T[];
  /** Add to array */
  addToArray: <T>(array: T[], item: T) => T[];
  /** Remove from array */
  removeFromArray: <T>(array: T[], matcher: (item: T) => boolean) => T[];
  /** Update nested object */
  updateNested: <T>(state: T, path: string[], value: any) => T;
}

Error Handling

Comprehensive error handling patterns are included:

// Error handling in reducers
on(EntityActions.loadEntitiesFailure, (state, { error }) => ({
  ...state,
  loading: false,
  error: typeof error === 'string' ? error : error.message || 'Unknown error'
})),

on(EntityActions.createEntityFailure, (state, { error }) => ({
  ...state,
  loading: false,
  error: `Failed to create entity: ${error}`
})),

// Clear errors on new operations
on(EntityActions.loadEntities, EntityActions.createEntity, (state) => ({
  ...state,
  error: null
}))

Reducer Testing

The generated reducer is fully testable with proper isolation:

// Generated reducer tests
describe('UserReducer', () => {
  describe('unknown action', () => {
    it('should return the previous state', () => {
      const action = {} as any;
      const result = userReducer(initialState, action);
      expect(result).toBe(initialState);
    });
  });

  describe('loadUsers action', () => {
    it('should set loading to true', () => {
      const action = UserActions.loadUsers();
      const result = userReducer(initialState, action);
      expect(result.loading).toBe(true);
      expect(result.error).toBe(null);
    });
  });

  describe('loadUsersSuccess action', () => {
    it('should update users and set loading to false', () => {
      const users = [{ id: '1', name: 'John' }];
      const action = UserActions.loadUsersSuccess({ users });
      const result = userReducer(initialState, action);
      expect(result.users).toEqual(users);
      expect(result.loading).toBe(false);
    });
  });
});

TypeScript Integration

Full TypeScript support with strict typing:

/**
 * Type-safe reducer function signature
 */
function createTypedReducer<T>(
  initialState: T,
  ...ons: On<T>[]
): ActionReducer<T>;

/**
 * Action reducer map for feature states
 */
interface ActionReducerMap<T> {
  [key: string]: ActionReducer<T[keyof T]>;
}

Performance Optimizations

The generated reducer includes performance considerations:

// Optimized state updates
on(EntityActions.updateEntitySuccess, (state, { entity }) => {
  const index = state.entities.findIndex(e => e.id === entity.id);
  if (index === -1) return state;
  
  const entities = [...state.entities];
  entities[index] = entity;
  
  return {
    ...state,
    entities
  };
});

// Conditional updates to prevent unnecessary renders
on(EntityActions.selectEntity, (state, { id }) => 
  state.selectedId === id ? state : { ...state, selectedId: id }
);

docs

action-generation.md

component-store.md

container-components.md

data-services.md

effect-generation.md

entity-management.md

feature-generation.md

index.md

ngrx-push-migration.md

reducer-generation.md

selector-generation.md

store-setup.md

utility-functions.md

tile.json