Introduction:
In modern web development, managing the application state is crucial to building robust and scalable applications. Traditional approaches like using local component states can become complex and hard to maintain as your application grows. This is where state management libraries like NGXS come to the rescue. NGXS is a powerful state management library for Angular applications that helps you centralize and organize your application state. In this blog, we’ll explore the key concepts of NGXS and provide a hands-on example to showcase its benefits.
If you want to learn about the NGRX, state management angular, you can refer here.
Understanding NGXS:
NGXS is inspired by Redux and centralizes the application state. It follows the unidirectional data flow pattern, making state changes predictable and traceable. NGXS promotes the use of immutable data and encourages developers to write pure functions to update the state, ensuring that the state remains immutable and changes are tracked efficiently.
Key Concepts of NGXS:
- State: The state represents the data that drives your application. It is stored in a centralized store and should be treated as immutable.
- Actions: Actions are plain JavaScript objects that describe an intention to change the state.
- Mutations: Mutations are responsible for updating the state based on the dispatched actions. They are pure functions that receive the current state and the action payload and return a new state.
- Store: The store is the central repository that holds the state of your application. It dispatches actions, applies mutations, and notifies subscribers about state changes.
- Selectors: Selectors are used to retrieve specific portions of the state from the store. They are pure functions that transform the raw state into a desired format for consumption.
Hands-On Example:
Let’s create a simple NGXS application to manage a list of tasks. Here are the steps:
1. Set up a new Angular project:
ng new ngxs-example
2. Install NGXS dependencies:
npm install @ngxs/store @ngxs/logger-plugin
3. Create a Task model:
// task.model.ts
export interface Task {
id: number;
title: string;
completed: boolean;
}
4. Create a state class:
// task.state.ts
import { State, Action, StateContext } from '@ngxs/store';
import { AddTask, ToggleTask } from './task.actions';
import { Task } from './task.model';
@State<Task[]>({
name: 'tasks',
defaults: []
})
export class TaskState {
@Action(AddTask)
addTask({ getState, setState }: StateContext<Task[]>, { payload }: AddTask) {
const state = getState();
const newTask: Task = {
id: Math.random(),
title: payload,
completed: false
};
setState([...state, newTask]);
}
@Action(ToggleTask)
toggleTask({ getState, patchState }: StateContext<Task[]>, { payload }: ToggleTask) {
const state = getState();
const taskIndex = state.findIndex(task => task.id === payload);
const updatedTasks = [...state];
updatedTasks[taskIndex].completed = !updatedTasks[taskIndex].completed;
patchState(updatedTasks);
}
}
5. Create actions:
// task.actions.ts
export class AddTask {
static readonly type = '[Tasks] Add';
constructor(public payload: string) {}
}
export class ToggleTask {
static readonly type = '[Tasks] Toggle';
constructor(public payload: number) {}
}
6. Register the NGXS module and plugins:
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgxsModule } from '@ngxs/store';
import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin';
import { AppComponent } from './app.component';
import { TaskState } from './task.state';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
NgxsModule.forRoot([TaskState]),
NgxsLoggerPluginModule.forRoot()
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
7. Use the state in a component:
// app.component.ts
import { Component } from '@angular/core';
import { Store } from '@ngxs/store';
import { AddTask, ToggleTask } from './task.actions';
import { Task } from './task.model';
@Component({
selector: 'app-root',
template: `
<div>
<input [(ngModel)]="taskInput" placeholder="Enter task" />
<button (click)="addTask()">Add Task</button>
<ul>
<li *ngFor="let task of tasks$ | async" [class.completed]="task.completed">
<span>{{ task.title }}</span>
<button (click)="toggleTask(task.id)">Toggle</button>
</li>
</ul>
</div>
`,
styles: [
`
.completed {
text-decoration: line-through;
}
`
]
})
export class AppComponent {
tasks$ = this.store.select(state => state.tasks);
taskInput = '';
constructor(private store: Store) {}
addTask() {
this.store.dispatch(new AddTask(this.taskInput));
this.taskInput = '';
}
toggleTask(taskId: number) {
this.store.dispatch(new ToggleTask(taskId));
}
}
Conclusion:
NGXS provides a powerful and intuitive way to manage application states in Angular projects. By following the principles of unidirectional data flow and immutability, NGXS helps you build scalable and maintainable applications. In this blog, we covered the key concepts of NGXS and demonstrated a practical example of how to use NGXS for state management. Now you’re ready to leverage NGXS to efficiently handle state in your Angular applications. Happy coding!
Finally, for more such posts, please follow our LinkedIn page- FrontEnd Competency.