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.
- 🏗️ 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
npm install ngrx-store-wrapperThe store wrapper auto-initializes itself on first use, thanks to Angular's runInInjectionContext. No manual setup needed beyond provideStore() and getInitialDynamicReducers().
✅ 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.
// app.config.ts
export const appConfig: ApplicationConfig = {
providers: [
provideStore({
...getInitialDynamicReducers(),
// Optional manually created reducers
counter: counterReducer
})
]
};// 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
});| 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 |
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()
@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');- 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(/*...*/);| Method | Description |
|---|---|
| set(key, value) | Creates/updates dynamic state |
| get(key) | Returns typed observable |
| remove(key) | Cleans up dynamic state |
| Method | Description |
|---|---|
| addEffect(config) | Creates managed effect |
| recallEffect(key) | Triggers effect |
| removeEffect(key) | Cleans up effect |
| 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 |
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
For more detailed information, check out our documentation.
For information about upcoming features, improvements, and our development priorities, check out our ROADMAP.md.
- 🚀 Live Demo - Try it out!
- 📚 Usage Examples - See it in action
- 🛠️ Source Code - Explore the library
- 📋 Roadmap - See what's coming next
- 💡 Feature Requests - Have an idea? Let us know by creating an issue!
MIT License