State Management in Angular Using NgRx Pt 1
State management is a crucial aspect of building scalable and maintainable Angular applications. As your app grows in complexity, keeping track of shared application state becomes challenging. This is where state management libraries like @ngrx/store
come to the rescue. In this article, we’ll explore how @ngrx/store
works and how it can simplify state management in your Angular app.
What is @ngrx/store
?
@ngrx/store
is a state management library inspired by the Redux pattern. It provides a centralized store to manage application state, ensuring a predictable and consistent flow of data throughout your application.
Core Concepts
Before diving into the implementation, let’s understand the core concepts of @ngrx/store
:
Store
The store is the single source of truth for your application state. It holds the entire state of your app in a single JavaScript object. Components access the state through the store and dispatch actions to modify the state.
Actions
Actions are payloads of information that describe what happened in your application. They are simple objects with a type
property that describes the action’s purpose. For instance, an action to increment a counter might have the type INCREMENT
, and an action to decrement it might have the type DECREMENT
.
Reducers
Reducers are pure functions responsible for transforming the state based on dispatched actions. They take the current state and an action as input and return a new state. Reducers are responsible for maintaining immutability, so they always return new objects instead of modifying the existing state.
Setting Up @ngrx/store
Step 1: Install Dependencies
First, let’s install the required packages using npm or yarn:
npm install @ngrx/store @ngrx/store-devtools --save
or
yarn add @ngrx/store @ngrx/store-devtools
Step 2: Create the AppState and Reducer
Next, we’ll create the AppState interface to define the structure of our state and the reducer to handle state updates:
counter.reducer.ts
import { createReducer, on } from '@ngrx/store';
import { increment, decrement } from './counter.actions';
export interface CounterState {
count: number;
}
export const initialState: CounterState = {
count: 0,
};
const _counterReducer = createReducer(
initialState,
on(increment, (state) => ({ ...state, count: state.count + 1 })),
on(decrement, (state) => ({ ...state, count: state.count - 1 }))
);
export function counterReducer(state: CounterState | undefined, action: Action) {
return _counterReducer(state, action);
}
Step 3: Dispatch Actions
In your components, you can now dispatch actions to modify the state:
counter.actions.ts
import { createAction } from '@ngrx/store';
export const increment = createAction('[Counter] Increment');
export const decrement = createAction('[Counter] Decrement');
counter-control.component.ts
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { increment, decrement } from '../counter.actions';
import { CounterState } from '../counter.reducer';
@Component({
selector: 'app-counter-control',
template: `
<button (click)="increment()">Increment</button>
<button (click)="decrement()">Decrement</button>
`,
})
export class CounterControlComponent {
constructor(private store: Store<CounterState>) {}
increment(): void {
this.store.dispatch(increment());
}
decrement(): void {
this.store.dispatch(decrement());
}
}
(ads)
Step 4: Select Data from the Store
To display the state in a component, use the async
pipe with the store.select()
method:
counter-display.component.ts
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '../counter.reducer';
@Component({
selector: 'app-counter-display',
template: '<p>Counter Value: {{ counterValue$ | async }}</p>',
})
export class CounterDisplayComponent {
counterValue$ = this.store.select((state) => state.count);
constructor(private store: Store<AppState>) {}
}
Conclusion
@ngrx/store
is a powerful state management solution for Angular applications. It provides a clear structure and a single source of truth for your app’s state, making it easier to manage and debug your application. By following the Redux pattern, @ngrx/store
helps you maintain a consistent flow of data and actions in your app.
Demo
(getCard) #type=(custom) #title=( Managing State in Angular Apps with NgRx - Part 2: Using HTTP and Effects)
In this article, we learned about the core concepts of @ngrx/store
, how to set it up, and how to use it to manage state in Angular components. By incorporating @ngrx/store
into your app, you can build scalable and maintainable Angular applications that are easier to reason about and extend.