Skip to content

himanshuarora111/ngrx-store-wrapper

Repository files navigation

ngrx-store-wrapper

A lightweight Angular library that lets you manage NgRx store state without writing actions, reducers, or effects manually, with built-in support for syncing to session and local storage.

Key Features

  • 🏗️ Dynamic Reducers - Create store slices at runtime
  • ⚡ Effect System - Auto-bound methods, polling, manual triggers
  • 💾 Persistence - localStorage/sessionStorage support
  • 🛡️ Type Safety - Full TypeScript support
  • 🧹 Automatic Cleanup - Subscription & resource management

Installation

npm install ngrx-store-wrapper

Compatibility

The store wrapper auto-initializes itself on first use, thanks to Angular's runInInjectionContext. No manual setup needed beyond provideStore() and getInitialDynamicReducers().

Angular & NgRx Compatibility:

✅ Compatible with Angular 15+ and NgRx 15+

  • Although peerDependencies previously targeted Angular 19+, the library is tested with Angular 16.2.0 and NgRx 16.2.0.
  • Expected to remain compatible through Angular 20.

Quick Start

1. Initialize Store

// app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    provideStore({
      ...getInitialDynamicReducers(),
      // Optional manually created reducers
      counter: counterReducer 
    })
  ]
};

2. Basic Usage

// Set state
storeWrapper.set('user', { name: 'Alice' });

// Get typed observable
interface User {
  name: string;
  age?: number;
}

storeWrapper.get<User>('user').subscribe(user => {
  console.log(user.name); // Type-safe access
});

// Effects with polling
storeWrapper.addEffect({
  key: 'liveData',
  serviceFn: dataService.fetch,
  intervalMs: 5000
});

Core Concepts

Dynamic vs Manually Created Reducers

Feature Dynamic Reducers Manually Created Reducers
Creation At runtime via set() Using NgRx createReducer
Modification Fully managed Protected from modification
Use Case Quick state needs Complex state logic

Persistence

You can persist selected store keys to localStorage or sessionStorage using:

storeWrapper.enablePersistence('user/settings', StorageType.Local);
  • localStorage: Persists even after the browser is closed
  • sessionStorage: Clears when the session ends (safer for sensitive data)

Automatically restores values on app start Manual cleanup via disablePersistence()

Effect System

@Injectable()
export class UserService {
  @AutoBind() // Preserves 'this' context
  getUser(id: string) {
    return this.http.get(`/users/${id}`);
  }
}

// Component
storeWrapper.addEffect({
  key: 'user',
  serviceFn: userService.getUser,
  args: '123',
  immediate: false
});

// Manually trigger later
storeWrapper.recallEffect('user');

Best Practices

  • Keys - Use consistent naming (e.g., 'feature/entity')
  • Effects - Always clean up in ngOnDestroy
  • Types - Leverage interfaces for complex state
  • Persistence - Prefer sessionStorage for sensitive data
// Good practice example
interface Settings {
  theme: 'light'|'dark';
  fontSize: number;
}

storeWrapper.enablePersistence('user/settings', StorageType.Local);
storeWrapper.get<Settings>('user/settings').subscribe(/*...*/);

API Reference

Store Operations

Method Description
set(key, value) Creates/updates dynamic state
get(key) Returns typed observable
remove(key) Cleans up dynamic state

Effect Methods

Method Description
addEffect(config) Creates managed effect
recallEffect(key) Triggers effect
removeEffect(key) Cleans up effect

Persistence Functions

Method Description
enablePersistence(key, storageType) Enables persistence for a store key using the specified storage type (Local/Session)
disablePersistence(key) Disables persistence for a store key

Working with Manually Created Reducers

For cases where you need more control than dynamic reducers provide:

Create a traditional NgRx reducer:

// counter.reducer.ts
const increment = createAction('[Counter] Increment');
export const counterReducer = createReducer(
  0,
  on(increment, (state) => state + 1)
);

Initialize with your store:

provideStore({
  counter: counterReducer, // Manually created
  ...getInitialDynamicReducers() // Dynamic
})

Key differences:

Manually created reducers:

  • Use NgRx actions for updates
  • Protected from set() operations
  • Better for complex state logic

Dynamic reducers:

  • Updated via set()
  • Perfect for simple state needs
  • Automatic action/reducer generation

Documentation

For more detailed information, check out our documentation.

Roadmap

For information about upcoming features, improvements, and our development priorities, check out our ROADMAP.md.

Resources

License

MIT License

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published