Belajar Redux - Custom Middleware & Enhancers
Episode 16 of 23

Belajar Redux - Custom Middleware & Enhancers

Episode ini membahas extensibility Redux: struktur custom middleware, menulis middleware untuk logging, tracking, dan telemetri, lalu memperluas store dengan enhancers dan komposisi middleware default RTK agar ekstensi bekerja bersama createAsyncThunk dan RTK Query.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Sampai episode 12 kita memakai middleware yang disediakan RTK. Namun aplikasi produksi sering butuh perilaku khusus: mencatat setiap action, mengirim telemetri ke analytics, atau berinteraksi dengan library luar. Episode 16 membuka kotak hitam tersebut — kalian akan belajar menulis custom middleware dan memahami enhancers untuk memperluas kemampuan store.

Middlewares dan enhancers adalah dua lapisan berbeda. Middleware mencegat action sebelum mencapai reducer. Enhancers membungkus store itu sendiri, memungkinkan mengganti cara dispatch, getState, dan subscribe bekerja. Keduanya bisa dikombinasikan dengan aman bersama middleware default RTK.

Struktur Middleware

Anatomi Middleware

Middleware berbentuk fungsi bersarang tiga level: (storeAPI) => (next) => (action). storeAPI berisi dispatch dan getState, next meneruskan action ke middleware berikutnya, dan lapisan terdalam yang dieksekusi per action:

JSsrc/app/middleware/logger.ts
import type { Middleware } from "@reduxjs/toolkit"
 
export const loggerMiddleware: Middleware = (storeAPI) => (next) => (action) => {
  const prevState = storeAPI.getState()
  const result = next(action)
  const nextState = storeAPI.getState()
  console.log("Action:", action.type, { prevState, nextState })
  return result
}

Urutan eksekusi penting: panggil next(action) lebih dulu bila middleware ingin mengamati state setelah reducer berjalan, atau tangani action sendiri dan jangan panggil next bila ingin mencegat sepenuhnya. next bukan dispatch — memanggil dispatch dari dalam middleware bisa memicu infinite loop.

Middleware untuk Telemetri

Telemetri biasanya berjalan tanpa memblokir reducer: catat event, lalu teruskan action. Tambahkan properti meta agar data tidak mencemari state:

JSMiddleware telemetri sederhana
import type { Middleware } from "@reduxjs/toolkit"
 
const TRACKED = ["order/created", "checkout/completed", "auth/loginSucceeded"]
 
export const telemetryMiddleware: Middleware = (storeAPI) => (next) => (action) => {
  const result = next(action)
  if (TRACKED.includes(action.type)) {
    const state = storeAPI.getState()
    navigator.sendBeacon?.("/api/telemetry", JSON.stringify({
      type: action.type,
      user: state.auth.user?.id,
      ts: Date.now(),
    }))
  }
  return result
}

navigator.sendBeacon mengirim telemetri secara asinkron tanpa memblokir render. Middleware tetap fokus pada efek samping; data telemetri tidak pernah masuk ke store.

Memasang Middleware Kustom

Bergabung dengan Middleware Default

Selalu kombinasikan middleware kustom dengan default RTK — tanpa itu, createAsyncThunk dan RTK Query tidak akan berfungsi. getDefaultMiddleware menerima konfigurasi dan menghasilkan array:

JSsrc/app/store.ts dengan custom middleware
import { configureStore } from "@reduxjs/toolkit"
import { loggerMiddleware } from "./middleware/logger"
import { telemetryMiddleware } from "./middleware/telemetry"
import { authSlice } from "../features/auth/authSlice"
 
export const store = configureStore({
  reducer: {
    auth: authSlice.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(
      loggerMiddleware,
      telemetryMiddleware,
    ),
})

.concat menambahkan middleware setelah default. Bila middleware harus melihat action lebih dulu, gunakan .prepend. Urutan menentukan siapa yang menangkap action terlebih dahulu dalam rantai.

Menonaktifkan Middleware Default

Beberapa middleware default bisa disesuaikan atau dimatikan. Contoh: mematikan serializable check untuk data yang memang tidak serializable:

JSKonfigurasi getDefaultMiddleware
middleware: (getDefaultMiddleware) =>
  getDefaultMiddleware({
    serializableCheck: {
      ignoredActions: ["drag/dropMove"],
      ignoredPaths: ["canvas.shapes"],
    },
  }),

Sebagian besar kasus tidak perlu mematikan check ini. Kalaupun harus, gunakan ignoredActions dan ignoredPaths agar cakupan pengecualian sesempit mungkin — jangan set false begitu saja.

Enhancers dan Ekstensi Store

Membungkus Store

Enhancer adalah fungsi yang menerima fungsi pembuat store dan mengembalikan store yang lebih kaya. Middleware itu sendiri adalah contoh enhancer: RTK Query di-injeksi lewat enhancer applyMiddleware internal. Contoh sederhana enhancer untuk menambahkan metode ke store:

JSEnhancer custom sederhana
import type { StoreEnhancer } from "@reduxjs/toolkit"
 
export const versionedStore: StoreEnhancer =
  (createStore) => (reducer, preloadedState) => {
    const store = createStore(reducer, preloadedState)
    return {
      ...store,
      version: "2026.1",
    }
  }

Enhancer membungkus store asli dan menambahkan properti. Pada praktiknya kalian jarang menulis enhancer sendiri — yang lebih umum adalah mengintegrasikan enhancer dari library eksternal yang menambah kemampuan store.

Menyusun Enhancer di configureStore

configureStore menerima enhancers sebagai fungsi yang bisa mengimbuhkan enhancer di sekitar default:

JSMenyusun enhancers
import { configureStore } from "@reduxjs/toolkit"
import { versionedStore } from "./enhancers/versionedStore"
 
export const store = configureStore({
  reducer: {
    auth: authSlice.reducer,
  },
  enhancers: (getDefaultEnhancers) =>
    getDefaultEnhancers().concat(versionedStore),
})

getDefaultEnhancers() mengembalikan enhancer bawaan seperti DevTools dan middleware. Menambah enhancer di akhir membuat wrapper terluar — cocok untuk logging store-level atau pembaruan eksternal.

Warning

Hati-hati dengan urutan: middleware yang di-dispatch dari dalam middleware lain, atau enhancer yang mengganti dispatch, bisa menimbulkan perilaku tak terduga. Uji setiap ekstensi dalam isolasi sebelum menggabungkannya.

Penutup

Custom middleware dan enhancers memberi Redux extensibility tanpa batas. Middleware mencegat action untuk logging, tracking, dan telemetri tanpa menyentuh reducer; enhancers membungkus store untuk integrasi dengan library eksternal. Keduanya bekerja bersama middleware default RTK — asalkan kalian memahami urutan eksekusi dan tidak mengganggu alur next.

Inti yang harus dibawa pulang:

  • Middleware berbentuk (storeAPI) => (next) => (action).
  • Panggil next(action) untuk meneruskan action ke reducer; jangan panggil dispatch di dalamnya.
  • Gabungkan middleware kustom dengan getDefaultMiddleware().concat(...).
  • Sesuaikan default middleware secara minimal lewat ignoredActions dan ignoredPaths.
  • Enhancers membungkus store dan dapat menambah metode atau mengganti perilaku dispatch.
  • Susun enhancers lewat opsi enhancers di configureStore.

Episode 17 berikutnya memperdalam RTK Query advanced — kalian akan mengeksplorasi pagination dan infinite query, GraphQL dengan graphql-request, streaming updates, prefetch berprioritas, codegen dari OpenAPI, serta custom baseQuery untuk multi-API dan auth refresh.

Belajar Redux - Custom Middleware & Enhancers | Belajar Redux