Monday

18-08-2025 Vol 19

Advanced NgRx Patterns for Enterprise Angular Applications

Pola NgRx Tingkat Lanjut untuk Aplikasi Angular Enterprise

NgRx adalah pustaka manajemen state yang kuat dan populer untuk aplikasi Angular.
Ini menerapkan pola arsitektur Redux, menyediakan cara terpusat dan prediktif untuk
mengelola state aplikasi Anda. Dalam aplikasi kecil, NgRx mungkin terasa berlebihan,
tetapi untuk aplikasi enterprise yang kompleks, NgRx dapat menjadi pengubah permainan,
membantu Anda menjaga kode yang bersih, terawat, dan mudah diuji.

Dalam posting blog ini, kita akan menjelajahi pola NgRx tingkat lanjut yang dapat
membantu Anda membangun aplikasi Angular enterprise yang lebih terukur dan mudah
dipelihara. Kita akan membahas berbagai topik, termasuk pemilihan entity, efek,
penanganan kesalahan, dan pengujian.

Daftar Isi

  1. Pendahuluan
  2. Mengapa Menggunakan NgRx dalam Aplikasi Enterprise?
  3. Pola Dasar NgRx: Pengingat Singkat
  4. Pemilihan Entity Tingkat Lanjut
    1. Pemilihan Entity Dasar
    2. Pemilihan dengan Memoization
    3. Pemilihan Properti dan Transformasi
    4. Pemilihan Relasional
  5. Efek NgRx Tingkat Lanjut
    1. Membatalkan Permintaan HTTP
    2. Menangani Berbagai Aksi dengan Operator
    3. Menggabungkan Aksi
    4. Menggunakan createEffect alih-alih @Effect
  6. Penanganan Kesalahan Tingkat Lanjut dengan NgRx
    1. Middleware Penanganan Kesalahan Global
    2. Aksi Kesalahan Spesifik
    3. Logika Coba Lagi (Retry Logic)
  7. Pemfaktoran Kode NgRx untuk Skalabilitas
    1. Modul Fitur (Feature Modules)
    2. Berbagi Kode Antar Modul
    3. Abstraksi Redux
  8. Pengujian Lanjutan Komponen dan Efek NgRx
    1. Unit Testing Reduksi
    2. Integrasi Efek
    3. End-to-End Testing
  9. Strategi Debu dan Optimalisasi Kinerja
    1. Debounce Time
    2. Memoization Lanjutan
    3. Kompresi State
  10. Alat dan Ekstensi NgRx
    1. Alur NgRx
    2. DevTools
    3. Ekstensi NgRx
  11. Praktik Terbaik untuk Aplikasi Angular Enterprise dengan NgRx
  12. Kesimpulan

1. Pendahuluan

Aplikasi Angular enterprise seringkali kompleks dan melibatkan pengelolaan data yang
signifikan. NgRx menawarkan solusi yang terstruktur dan prediktif untuk mengelola
state aplikasi, sehingga memudahkan untuk memahami, memelihara, dan menguji kode.

Dalam posting blog ini, kita akan membahas pola NgRx tingkat lanjut yang melampaui
dasar-dasar dan mengatasi tantangan yang unik dalam aplikasi enterprise. Kita akan
menjelajahi teknik untuk pemilihan data yang efisien, penanganan efek yang kuat,
penanganan kesalahan yang komprehensif, dan strategi untuk membuat kode NgRx Anda
lebih terukur dan mudah dipelihara.

2. Mengapa Menggunakan NgRx dalam Aplikasi Enterprise?

NgRx membawa sejumlah manfaat ke aplikasi Angular enterprise:

  1. Manajemen State Terpusat: NgRx menyediakan penyimpanan state tunggal
    untuk seluruh aplikasi Anda, sehingga memudahkan untuk memahami dan mengelola state.
  2. Prediktabilitas: State diperbarui dengan cara yang prediktif dan
    terkontrol, melalui reduksi. Ini membuat debugging dan pengujian lebih mudah.
  3. Keterukuran: NgRx membantu Anda mengatur kode Anda dengan cara yang
    modular dan terukur.
  4. Kemudahan Pemeliharaan: NgRx membuat kode Anda lebih mudah dipelihara
    dengan menyediakan cara yang jelas dan terstruktur untuk mengelola state aplikasi.
  5. Kemudahan Pengujian: Arsitektur NgRx membuatnya mudah untuk
    melakukan unit testing terhadap reduksi dan efek Anda.
  6. Perfoma: Dengan teknik seperti memoization, NgRx dapat dioptimalkan
    untuk performa bahkan dalam aplikasi kompleks.

3. Pola Dasar NgRx: Pengingat Singkat

Sebelum masuk ke pola tingkat lanjut, mari kita lakukan pengingat cepat tentang
konsep dasar NgRx:

  • State: Data aplikasi Anda. Ini adalah sumber kebenaran tunggal untuk
    aplikasi Anda.
  • Aksi: Objek JavaScript sederhana yang mewakili niat untuk mengubah
    state.
  • Reduksi: Fungsi murni yang mengambil state dan aksi saat ini sebagai
    input dan mengembalikan state baru. Reduksi menentukan bagaimana state berubah sebagai
    respons terhadap aksi.
  • Efek: Sisi-efek yang mendengarkan aksi dan melakukan tugas-tugas
    seperti panggilan API, navigasi, dan interaksi lain dengan dunia luar.
  • Pemilih: Fungsi yang digunakan untuk mengekstrak potongan data dari state.
    Pemilih dapat menggunakan memoization untuk meningkatkan performa.
  • Toko (Store): Sumber kebenaran tunggal yang menyimpan state aplikasi.
    Komponen berinteraksi dengan store dengan mengirim aksi dan memilih data.

4. Pemilihan Entity Tingkat Lanjut

Pemilihan entity adalah aspek penting dari aplikasi NgRx. Ini melibatkan pemilihan
potongan data tertentu dari state store. Teknik pemilihan yang efisien dapat
memperbaiki performa dan mengurangi rendering yang tidak perlu.

4.1. Pemilihan Entity Dasar

Pendekatan paling dasar adalah menggunakan pemilih sederhana untuk mengambil
sepotong state tertentu. Misalnya:


    // Selector dasar
    export const selectTodosState = createFeatureSelector<TodosState>('todos');

    export const selectAllTodos = createSelector(
      selectTodosState,
      (state: TodosState) => state.todos
    );
  

4.2. Pemilihan dengan Memoization

Memoization adalah teknik pengoptimalan yang menyimpan hasil fungsi dan mengembalikan
hasil yang di-cache ketika input yang sama terjadi lagi. Ini dapat secara signifikan
meningkatkan performa pemilih, terutama untuk perhitungan yang kompleks.


    import { createSelector } from '@ngrx/store';
    import { Todo } from './models/todo.model';

    export const selectCompletedTodos = createSelector(
      selectAllTodos,
      (todos: Todo[]) => todos.filter(todo => todo.completed)
    );
  

Dalam contoh ini, selectCompletedTodos hanya akan menghitung ulang
jika selectAllTodos mengembalikan array baru. Jika tidak, ia akan
mengembalikan hasil yang di-cache.

4.3. Pemilihan Properti dan Transformasi

Anda dapat membuat pemilih yang tidak hanya memilih data tetapi juga mengubahnya.
Ini sangat berguna untuk memformat data untuk tampilan atau untuk menghitung nilai
yang diturunkan.


    export const selectTodoCount = createSelector(
      selectAllTodos,
      (todos: Todo[]) => todos.length
    );

    export const selectCompletedTodoCount = createSelector(
      selectCompletedTodos,
      (todos: Todo[]) => todos.length
    );
  

4.4. Pemilihan Relasional

Dalam aplikasi enterprise, seringkali Anda memiliki data relasional. NgRx Entity
memberikan cara yang nyaman untuk mengelola dan memilih data entitas.


    import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity';

    export interface TodoState extends EntityState<Todo> {
      // tambahkan properti state spesifik entitas di sini
      loading: boolean;
    }

    export const adapter: EntityAdapter<Todo> = createEntityAdapter<Todo>();

    export const initialState: TodoState = adapter.getInitialState({
      // setel state awal spesifik entitas di sini
      loading: false
    });

    export const {
      selectIds,
      selectEntities,
      selectAll,
      selectTotal,
    } = adapter.getSelectors();

    export const selectAllTodos = createSelector(
      selectTodosState,
      selectAll
    );

    export const selectTodoEntities = createSelector(
      selectTodosState,
      selectEntities
    );

    export const selectTodoById = (id: string) => createSelector(
      selectTodoEntities,
      entities => entities[id]
    );
  

NgRx Entity menyediakan berbagai pemilih bawaan untuk mengambil data entitas.
Anda juga dapat membuat pemilih khusus untuk persyaratan spesifik Anda.

5. Efek NgRx Tingkat Lanjut

Efek digunakan untuk menangani efek samping dalam aplikasi NgRx Anda, seperti membuat
permintaan HTTP, berinteraksi dengan localStorage, atau menavigasi ke halaman lain.

5.1. Membatalkan Permintaan HTTP

Dalam beberapa skenario, Anda mungkin perlu membatalkan permintaan HTTP yang sedang
berlangsung. Ini dapat dilakukan menggunakan operator RxJS seperti `takeUntil` atau
`switchMap`.


    import { Injectable } from '@angular/core';
    import { Actions, createEffect, ofType } from '@ngrx/effects';
    import { of } from 'rxjs';
    import { catchError, map, switchMap, takeUntil } from 'rxjs/operators';
    import { HttpClient } from '@angular/common/http';

    import * as TodoActions from './todo.actions';

    @Injectable()
    export class TodoEffects {

      loadTodos$ = createEffect(() => this.actions$.pipe(
        ofType(TodoActions.loadTodos),
        switchMap(() => this.http.get<Todo[]>('/api/todos').pipe(
          map(todos => TodoActions.loadTodosSuccess({ todos })),
          catchError(error => of(TodoActions.loadTodosFailure({ error })))
        ))
      ));

      // Membatalkan efek
      stopLoadTodos$ = createEffect(() => this.actions$.pipe(
        ofType(TodoActions.stopLoadTodos),
        map(() => TodoActions.clearTodos()) // Contoh aksi untuk membersihkan state
      ));

      loadTodosWithCancellation$ = createEffect(() => this.actions$.pipe(
        ofType(TodoActions.loadTodosWithCancellation),
        switchMap(() => this.http.get<Todo[]>('/api/todos').pipe(
          takeUntil(this.actions$.pipe(ofType(TodoActions.stopLoadTodos))),
          map(todos => TodoActions.loadTodosSuccess({ todos })),
          catchError(error => of(TodoActions.loadTodosFailure({ error })))
        ))
      ));

      constructor(private actions$: Actions, private http: HttpClient) {}
    }
  

Dalam contoh ini, `loadTodosWithCancellation$` membatalkan permintaan HTTP jika aksi
`stopLoadTodos` dikirimkan.

5.2. Menangani Berbagai Aksi dengan Operator

Efek dapat mendengarkan berbagai aksi menggunakan operator RxJS seperti
`mergeMap` atau `exhaustMap`.


    loadTodosAndUsers$ = createEffect(() => this.actions$.pipe(
      ofType(TodoActions.loadTodos, UserActions.loadUsers),
      mergeMap(() => {
        const todos$ = this.http.get<Todo[]>('/api/todos');
        const users$ = this.http.get<User[]>('/api/users');

        return forkJoin([todos$, users$]).pipe(
          map(([todos, users]) => {
            return TodoActions.loadTodosAndUsersSuccess({ todos, users });
          }),
          catchError(error => of(TodoActions.loadTodosAndUsersFailure({ error })))
        );
      })
    ));
  

Dalam contoh ini, `loadTodosAndUsers$` dipicu oleh aksi `loadTodos` atau
`loadUsers`. Ini membuat permintaan HTTP paralel untuk data todos dan pengguna dan
kemudian menggabungkan hasilnya.

5.3. Menggabungkan Aksi

Dalam beberapa kasus, Anda mungkin perlu mengirimkan beberapa aksi dari satu efek.
Ini dapat dilakukan menggunakan operator RxJS seperti `concatMap` atau
`exhaustMap`.


    createTodo$ = createEffect(() => this.actions$.pipe(
      ofType(TodoActions.createTodo),
      concatMap(action => this.http.post<Todo>('/api/todos', action.todo).pipe(
        map(todo => [
          TodoActions.createTodoSuccess({ todo }),
          NotificationActions.showSuccess({ message: 'Todo dibuat!' })
        ]),
        concatAll(), // Menggabungkan array aksi menjadi aliran aksi
        catchError(error => of(TodoActions.createTodoFailure({ error })))
      ))
    ));
  

Dalam contoh ini, `createTodo$` mengirimkan aksi `createTodoSuccess` dan
`showSuccess` setelah todo berhasil dibuat.

5.4. Menggunakan createEffect alih-alih @Effect

Meskipun `@Effect` sebelumnya merupakan cara standar untuk membuat efek, `createEffect`
direkomendasikan untuk sintaks yang lebih jelas dan mudah dipahami.

Menggunakan `@Effect` (tidak direkomendasikan):


    import { Injectable } from '@angular/core';
    import { Actions, Effect, ofType } from '@ngrx/effects';
    import { Observable } from 'rxjs';
    import { map } from 'rxjs/operators';

    @Injectable()
    export class TodoEffects {
      @Effect()
      loadTodos$: Observable<any> = this.actions$.pipe(
        ofType('[Todo] Load Todos'),
        map(() => ({ type: '[Todo] Load Todos Success' }))
      );

      constructor(private actions$: Actions) {}
    }
  

Menggunakan `createEffect` (direkomendasikan):


    import { Injectable } from '@angular/core';
    import { Actions, createEffect, ofType } from '@ngrx/effects';
    import { map } from 'rxjs/operators';

    @Injectable()
    export class TodoEffects {
      loadTodos$ = createEffect(() => this.actions$.pipe(
        ofType('[Todo] Load Todos'),
        map(() => ({ type: '[Todo] Load Todos Success' }))
      ));

      constructor(private actions$: Actions) {}
    }
  

`createEffect` memaksa Anda untuk mengembalikan aliran, membuat alur data eksplisit
dan lebih mudah diikuti.

6. Penanganan Kesalahan Tingkat Lanjut dengan NgRx

Penanganan kesalahan sangat penting dalam aplikasi enterprise. NgRx menyediakan
beberapa cara untuk menangani kesalahan dengan anggun.

6.1. Middleware Penanganan Kesalahan Global

Anda dapat membuat middleware penanganan kesalahan global yang mencegat semua aksi
yang gagal dan menangani kesalahan tersebut secara terpusat.


    import { Injectable } from '@angular/core';
    import { Actions, createEffect, ofType } from '@ngrx/effects';
    import { of } from 'rxjs';
    import { catchError } from 'rxjs/operators';

    @Injectable()
    export class GlobalErrorEffects {
      constructor(private actions$: Actions) {}

      globalError$ = createEffect(() => this.actions$.pipe(
        ofType(
          // cantumkan semua aksi kegagalan di sini
          '[Todo] Load Todos Failure',
          '[Todo] Create Todo Failure'
        ),
        catchError((error, caught) => {
          console.error('Aksi Gagal:', error);
          // kirim aksi untuk menampilkan pesan kesalahan global
          return of({ type: '[Global] Show Error', error });
        })
      ));
    }
  

Middleware ini mencegat semua aksi yang gagal dan mencatat kesalahan ke konsol.
Anda juga dapat mengirim aksi untuk menampilkan pesan kesalahan global kepada pengguna.

6.2. Aksi Kesalahan Spesifik

Cara lain untuk menangani kesalahan adalah dengan mengirimkan aksi kesalahan spesifik
ketika terjadi kesalahan. Ini memungkinkan Anda menangani kesalahan secara berbeda
tergantung pada aksi yang gagal.


    // dalam efek Anda
    loadTodos$ = createEffect(() => this.actions$.pipe(
      ofType('[Todo] Load Todos'),
      switchMap(() => this.http.get<Todo[]>('/api/todos').pipe(
        map(todos => ({ type: '[Todo] Load Todos Success', todos })),
        catchError(error => of({ type: '[Todo] Load Todos Failure', error }))
      ))
    ));
  

Dalam contoh ini, aksi `[Todo] Load Todos Failure` dikirimkan ketika permintaan
HTTP gagal. Anda kemudian dapat menangani aksi ini di reducer Anda dan memperbarui
state yang sesuai.

6.3. Logika Coba Lagi (Retry Logic)

Dalam beberapa kasus, Anda mungkin ingin mencoba lagi permintaan yang gagal secara
otomatis. Ini dapat dilakukan menggunakan operator RxJS seperti `retry` atau
`retryWhen`.


    import { retryWhen, delay, take } from 'rxjs/operators';

    loadTodos$ = createEffect(() => this.actions$.pipe(
      ofType('[Todo] Load Todos'),
      switchMap(() => this.http.get<Todo[]>('/api/todos').pipe(
        retryWhen(errors => errors.pipe(delay(1000), take(3))), // Coba lagi hingga 3 kali dengan penundaan 1 detik
        map(todos => ({ type: '[Todo] Load Todos Success', todos })),
        catchError(error => of({ type: '[Todo] Load Todos Failure', error }))
      ))
    ));
  

Dalam contoh ini, permintaan HTTP akan dicoba lagi hingga 3 kali dengan penundaan
1 detik antara setiap percobaan.

7. Pemfaktoran Kode NgRx untuk Skalabilitas

Saat aplikasi Anda bertambah besar, penting untuk memfaktorkan kode NgRx Anda agar
tetap teratur dan mudah dipelihara.

7.1. Modul Fitur (Feature Modules)

Salah satu cara untuk memfaktorkan kode NgRx Anda adalah dengan menggunakan modul
fitur. Modul fitur adalah cara untuk mengelompokkan state, aksi, reduksi, efek, dan
pemilih terkait menjadi satu modul yang koheren.


    // todo.module.ts
    import { NgModule } from '@angular/core';
    import { StoreModule } from '@ngrx/store';
    import { EffectsModule } from '@ngrx/effects';

    import { todoReducer } from './todo.reducer';
    import { TodoEffects } from './todo.effects';

    @NgModule({
      imports: [
        StoreModule.forFeature('todos', todoReducer),
        EffectsModule.forFeature([TodoEffects])
      ]
    })
    export class TodoModule {}
  

Dalam contoh ini, modul fitur `TodoModule` berisi semua kode NgRx terkait dengan
fitur todos.

7.2. Berbagi Kode Antar Modul

Dalam beberapa kasus, Anda mungkin perlu berbagi kode antar modul fitur yang berbeda.
Ini dapat dilakukan dengan membuat modul bersama yang berisi kode umum.


    // shared.module.ts
    import { NgModule } from '@angular/core';
    import { CommonModule } from '@angular/common';

    @NgModule({
      imports: [CommonModule],
      exports: [CommonModule]
    })
    export class SharedModule {}
  

Dalam contoh ini, modul bersama `SharedModule` berisi modul `CommonModule`, yang
diperlukan oleh banyak komponen.

7.3. Abstraksi Redux

Untuk aplikasi skala enterprise, Anda mungkin ingin lebih abstrakkan interaksi langsung
dengan Redux. Ini dapat dilakukan dengan memperkenalkan layanan pembantu atau abstraksi
yang merangkum aksi pengiriman dan pemilihan state.


    // todo.service.ts
    import { Injectable } from '@angular/core';
    import { Store } from '@ngrx/store';
    import * as TodoActions from './todo.actions';
    import * as TodoSelectors from './todo.selectors';
    import { Todo } from './models/todo.model';

    @Injectable({
      providedIn: 'root'
    })
    export class TodoService {

      constructor(private store: Store) {}

      loadTodos(): void {
        this.store.dispatch(TodoActions.loadTodos());
      }

      getTodos(): Observable<Todo[]> {
        return this.store.select(TodoSelectors.selectAllTodos);
      }

      createTodo(todo: Todo): void {
        this.store.dispatch(TodoActions.createTodo({ todo }));
      }

      // Metode tambahan untuk memperbarui, menghapus, dll.
    }
  

Ini menyediakan lapisan abstraksi di atas implementasi NgRx, sehingga memudahkan untuk
berubah atau meningkatkan kode NgRx tanpa memengaruhi komponen Anda secara langsung.

8. Pengujian Lanjutan Komponen dan Efek NgRx

Pengujian sangat penting untuk memastikan bahwa kode NgRx Anda berfungsi dengan benar.

8.1. Unit Testing Reduksi

Unit testing reduksi melibatkan pengujian bahwa reduksi Anda menghasilkan state yang
benar untuk aksi tertentu.


    import { todoReducer, initialState } from './todo.reducer';
    import * as TodoActions from './todo.actions';
    import { Todo } from './models/todo.model';

    describe('Todo Reducer', () => {
      it('harus mengembalikan state awal', () => {
        const action = {} as any;
        const state = todoReducer(undefined, action);

        expect(state).toBe(initialState);
      });

      it('harus memuat todos', () => {
        const todos: Todo[] = [{ id: '1', name: 'Todo 1', completed: false }];
        const action = TodoActions.loadTodosSuccess({ todos });
        const state = todoReducer(initialState, action);

        expect(state.entities['1']).toEqual(todos[0]);
      });
    });
  

Dalam contoh ini, kita menguji bahwa reduksi menghasilkan state awal yang benar dan
bahwa ia memuat todos dengan benar.

8.2. Integrasi Efek

Integrasi efek melibatkan pengujian bahwa efek Anda mengirimkan aksi yang benar dan
bahwa mereka menangani kesalahan dengan benar.


    import { TestBed } from '@angular/core/testing';
    import { provideMockActions } from '@ngrx/effects/testing';
    import { Observable, of } from 'rxjs';
    import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

    import { TodoEffects } from './todo.effects';
    import * as TodoActions from './todo.actions';
    import { Todo } from './models/todo.model';

    describe('Todo Effects', () => {
      let actions$: Observable<any>;
      let effects: TodoEffects;
      let httpTestingController: HttpTestingController;

      beforeEach(() => {
        TestBed.configureTestingModule({
          imports: [HttpClientTestingModule],
          providers: [
            TodoEffects,
            provideMockActions(() => actions$)
          ]
        });

        effects = TestBed.inject(TodoEffects);
        httpTestingController = TestBed.inject(HttpTestingController);
      });

      it('harus memuat todos', () => {
        const todos: Todo[] = [{ id: '1', name: 'Todo 1', completed: false }];
        const action = TodoActions.loadTodos();
        actions$ = of(action);

        effects.loadTodos$.subscribe(result => {
          expect(result).toEqual(TodoActions.loadTodosSuccess({ todos }));
        });

        const req = httpTestingController.expectOne('/api/todos');
        expect(req.request.method).toBe('GET');
        req.flush(todos);
      });
    });
  

Dalam contoh ini, kita menguji bahwa efek memuat todos dengan benar dan bahwa ia
mengirimkan aksi `loadTodosSuccess` yang benar.

8.3. End-to-End Testing

End-to-end testing melibatkan pengujian bahwa seluruh aplikasi berfungsi dengan benar.
Ini dapat dilakukan menggunakan alat seperti Cypress atau Selenium.

End-to-end testing tidak spesifik untuk NgRx, tetapi penting untuk memastikan bahwa
aplikasi Anda berfungsi dengan benar secara keseluruhan.

9. Strategi Debu dan Optimalisasi Kinerja

Dengan aplikasi enterprise, penting untuk mengoptimalkan performa dan memastikan
aplikasi responsif.

9.1. Debounce Time

`debounceTime` adalah operator RxJS yang dapat digunakan untuk membatasi frekuensi
aksi dikirimkan. Ini dapat berguna untuk meningkatkan performa saat pengguna mengetik
di kolom pencarian atau melakukan tindakan lain yang memicu banyak aksi.


    searchTodos$ = createEffect(() => this.actions$.pipe(
      ofType(TodoActions.searchTodos),
      debounceTime(300), // Tunggu 300ms setelah ketikan terakhir
      switchMap(action => this.http.get<Todo[]>(`/api/todos?q=${action.query}`).pipe(
        map(todos => TodoActions.searchTodosSuccess({ todos })),
        catchError(error => of(TodoActions.searchTodosFailure({ error })))
      ))
    ));
  

Dalam contoh ini, `searchTodos$` hanya membuat permintaan HTTP setelah pengguna berhenti
mengetik selama 300ms.

9.2. Memoization Lanjutan

Selain memoization dasar, Anda dapat menggunakan pustaka seperti `reselect` untuk
memoization yang lebih kompleks. `reselect` memungkinkan Anda membuat pemilih yang
dapat memoize hasil dari berbagai input.


    import { createSelector } from 'reselect';

    const selectTodos = (state: AppState) => state.todos.todos;
    const selectQuery = (state: AppState) => state.todos.query;

    export const selectFilteredTodos = createSelector(
      selectTodos,
      selectQuery,
      (todos, query) => todos.filter(todo => todo.name.includes(query))
    );
  

`reselect` secara efisien me-memoize pemilih berdasarkan input mereka, yang
meminimalkan perhitungan yang tidak perlu.

9.3. Kompresi State

Untuk state yang sangat besar, pertimbangkan untuk mengompres state sebelum
menyimpannya ke localStorage atau mengirimkannya melalui jaringan. Ini dapat mengurangi
ukuran state secara signifikan dan meningkatkan performa.


    import { compress, decompress } from 'lz-string';

    // Mengompres state
    const compressedState = compress(JSON.stringify(state));

    // Mendekompres state
    const decompressedState = JSON.parse(decompress(compressedState));
  

10. Alat dan Ekstensi NgRx

Ada beberapa alat dan ekstensi yang dapat membantu Anda mengembangkan aplikasi NgRx
Anda.

10.1. Alur NgRx

Alur NgRx adalah alat baris perintah yang dapat membantu Anda membuat kode NgRx yang
boilerplate.


    ng generate @ngrx/schematics:store State --module app.module.ts --statePath app.state.ts
  

Alur NgRx dapat menghemat banyak waktu dan upaya dengan menghasilkan kode yang
diperlukan untuk state, aksi, reduksi, efek, dan pemilih Anda.

10.2. DevTools

NgRx DevTools adalah ekstensi browser yang memungkinkan Anda memeriksa state NgRx
Anda, mengirimkan aksi, dan memutar ulang perubahan state.

NgRx DevTools adalah alat yang tak ternilai harganya untuk debugging dan memahami
aplikasi NgRx Anda.

10.3. Ekstensi NgRx

Ada beberapa ekstensi NgRx yang dapat membantu Anda mengembangkan aplikasi NgRx Anda.
Beberapa ekstensi populer meliputi:

  • NgRx Data: Menyediakan cara yang mudah dan terstruktur untuk
    mengelola data di aplikasi NgRx Anda.
  • NgRx Entity: Memungkinkan Anda mengelola koleksi entitas secara
    efisien.
  • NgRx Router: Menawarkan integrasi yang lancar dengan router Angular.

11. Praktik Terbaik untuk Aplikasi Angular Enterprise dengan NgRx

Berikut adalah beberapa praktik terbaik untuk menggunakan NgRx dalam aplikasi Angular
enterprise:

omcoding

Leave a Reply

Your email address will not be published. Required fields are marked *