Episode ini membahas state management dan reactive patterns: pola pengelolaan state dengan RxJS, BehaviorSubject dan ReplaySubject sebagai state services, pengenalan NgRx atau Akita, serta cara mengelola side effects aplikasi secara terstruktur.

Semakin besar aplikasi, semakin banyak state yang harus dikelola: user login, keranjang, filter, hasil pencarian. Menaruh semua state di komponen akan membuat kode sulit diprediksi dan dites.
Episode 10 membahas state management dengan pola RxJS, BehaviorSubject dan ReplaySubject sebagai state services, pengenalan library seperti NgRx atau Akita, serta pengelolaan side effects yang terstruktur. Kalian akan melihat pola yang menghubungkan cara berpikir reactive dengan kebutuhan aplikasi nyata.
State management yang baik mengikuti aliran satu arah: komponen mengirim aksi ke service, service memperbarui state, dan state baru mengalir kembali ke komponen lewat Observable. Tidak ada komponen yang memodifikasi state milik komponen lain secara langsung.
Pola paling sederhana adalah satu service yang menjadi sumber state dan mengekspos stream:
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Todo } from './todo.model';
@Injectable({ providedIn: 'root' })
export class TodoService {
private readonly state = new BehaviorSubject<Todo[]>([]);
readonly todos$ = this.state.asObservable();
setTodos(data: Todo[]): void {
this.state.next(data);
}
tambah(todo: Todo): void {
this.state.next([...this.state.getValue(), todo]);
}
}BehaviorSubject menyimpan nilai terkini dan mengirimkannya ke subscriber baru. todos$ adalah stream publik yang bisa di-subscribe komponen, sementara state tetap privat. Semua perubahan state lewat method service — itulah satu-satunya jalur.
import { ReplaySubject } from 'rxjs';
const notif$ = new ReplaySubject<string>(3);
notif$.next('Perubahan 1');
notif$.next('Perubahan 2');
notif$.subscribe((msg) => console.log(msg));new ReplaySubject<string>(3) menyimpan tiga pesan terakhir. Saat subscribe terjadi setelah dua next, kedua pesan itu langsung diterima subscriber. Pola ini berguna untuk cache kecil atau event yang boleh terlewat.
Komponen menerima state lewat todos$ dan merender dengan pipe async, yang otomatis mengelola subscription:
<li *ngFor="let todo of todos$ | async; trackBy: trackById">
{{ todo.judul }}
</li>todos$ | async men-subscribe stream dan membersihkannya saat komponen dihancurkan — tanpa ngOnDestroy manual dan tanpa risiko memory leak.
NgRx membawa pola Redux ke Angular: state tunggal, aksi untuk setiap perubahan, dan reducer murni yang menghitung state baru.
import { createAction, createReducer, on } from '@ngrx/store';
export const tambahTodo = createAction('[Todo] Tambah', (judul: string) => ({ judul }));
const initialState: string[] = [];
export const todoReducer = createReducer(
initialState,
on(tambahTodo, (state, { judul }) => [...state, judul]),
);createAction mendefinisikan aksi, createReducer membentuk reducer. Keuntungan NgRx: state dapat di-debug dengan DevTools, satu sumber kebenaran global, dan pola yang konsisten untuk tim besar. Harganya: banyak boilerplate — pertimbangkan hanya untuk state yang benar-benar global dan kompleks.
Akita adalah state management yang lebih ringan dengan pendekatan stores dan query, dan memakai API yang lebih mirip OOP. Untuk sebagian besar aplikasi, kombinasi service dengan BehaviorSubject (atau signal) sudah cukup; library eksternal baru layak ditambahkan ketika kompleksitas benar-benar menuntut.
Side effects — request HTTP, penyimpanan localStorage, logging — sebaiknya tidak berserakan di komponen. Pola yang rapi: service state hanya bertanggung jawab atas state, service data menangani HTTP, dan komponen hanya menyatukan keduanya.
export class TodoService {
private readonly state = new BehaviorSubject<Todo[]>([]);
readonly todos$ = this.state.asObservable();
muat(): void {
this.http.get<Todo[]>(url).subscribe({
next: (data) => this.state.next(data),
error: (err) => console.error('Gagal memuat todo', err),
});
}
}Method muat memicu HTTP, lalu hasilnya masuk ke state melalui state.next. Komponen cukup memanggil muat() dan membaca todos$. Side effects terkumpul di service sehingga komponen tetap ramping dan mudah diuji.
Inti yang harus dibawa pulang:
BehaviorSubject menyimpan nilai terkini; ReplaySubject menyimpan sejumlah nilai terakhir.async mengelola subscription stream secara otomatis.Di episode 11 selanjutnya kita akan membahas configuration dan environment — memakai environment files dan build configurations, mengatur Angular CLI configuration dan build targets, mengelola feature flags dan API endpoint, serta menangani secrets dan production settings dengan aman.