Advance Caching dengan RTK Query

Timotius Nugroho
Arunatech
Published in
4 min readSep 25, 2023

Teknik Caching digunakan untuk mengoptimasi Call API di sisi Front End. Dengan memanfaatkan data call API yang sudah ter-cache oleh browser, menjadikan user experience lebih bagus karena data yang diterima user bisa terprovide dengan cepat. Serta dari sisi Back End, query yang ter-eksekusi dapat berkurang.

RTK Query adalah salah satu tool untuk melakukan data feching serta caching. RTK Query memudahkan kita untuk melakukan invalidate secara otomatis pada data yang ter-cache secara spesifik dengan menerapkan providing & Invalidating tags.

Dengan menggunakan tags, Invalidate cache akan dilakukan dengan merequest data baru dari server untuk mengganti data yang sudah ter-cache. Jadi akan ada 2 jenis call API yang dilakukan yaitu:

  1. Call API untuk mutasi data di database (POST/PUT, dst).
  2. Call API untuk get data terupdate dari database (GET).

Untuk beberapa case, terdapat teknik yang lebih OK, sehingga Call API cukup dilakukan yang no.1 saja, yaitu dengan cara mengupdate cache secara manual pada saat mutasi dimulai atau sesudah mutasi berhasil di lakukan. Sebelum pembahasan lebih dalam, ada baiknya kita membaca terlebih dahulu bagaimana caranya invalidate cache (otomatis) RTK Query disini.

Optimistic Update

Optimistic update dilakukan untuk meng-update cache sesaat setelah mutasi ter-trigger, tidak peduli mutasi tersebut akan berhasil atau gagal. Apabila mutasi gagal dilakukan kita bisa membatalkan update cache di dalam block catch.

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

import type { Post } from './types'

const api = createApi({
baseQuery: fetchBaseQuery({
baseUrl: '/',
}),
tagTypes: ['Post'],
endpoints: (build) => ({
getPost: build.query<Post, number>({
query: (id) => `post/${id}`,
providesTags: ['Post'],
}),
updatePost: build.mutation<void, Pick<Post, 'id'> & Partial<Post>>({
query: ({ id, ...patch }) => ({
url: `post/${id}`,
method: 'PATCH',
body: patch,
}),
async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {
const patchResult = dispatch(
api.util.updateQueryData('getPost', id, (draft) => {
Object.assign(draft, patch)
})
)
try {
await queryFulfilled
} catch {
patchResult.undo()

/**
* Alternatively, on failure you can invalidate the corresponding cache tags
* to trigger a re-fetch:
* dispatch(api.util.invalidateTags(['Post']))
*/
}
},
}),
}),
})
  1. Ketika Query updatePost di eksekusi, fungsi onQueryStarted akan ter-eksekusi.
  2. onQueryStarted akan mempassing parameter id dan patch (body dari mutasi). Setelah itu, cache query getPost dengan id yang bersangkutan akan diupdate dengan object patch.
  3. Dalam block try kita akan menunggu querFulfilled hingga data berhasil terupdate di sisi server.
  4. Apabila terjadi error, dalam block catch akan membatalkan update cache yang sudah dilakukan dengan .undo(). Atau dengan cara lain, yaitu dengan meng-invalidate tag “Post” sehingga query getPost melakukan re-fetch.

Pessimistic Update

Pessimistic update dilakukan untuk meng-update cache setelah mutasi berhasil dilakukan, dan apabila mutasi gagal, maka cache tidak akan terupdate.

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
import type { Post } from './types'

const api = createApi({
baseQuery: fetchBaseQuery({
baseUrl: '/',
}),
tagTypes: ['Post'],
endpoints: (build) => ({
getPost: build.query<Post, number>({
query: (id) => `post/${id}`,
providesTags: ['Post'],
}),
updatePost: build.mutation<Post, Pick<Post, 'id'> & Partial<Post>>({
query: ({ id, ...patch }) => ({
url: `post/${id}`,
method: 'PATCH',
body: patch,
}),
async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {
try {
await queryFulfilled
const patchResult = dispatch(
api.util.updateQueryData('getPost', id, (draft) => {
Object.assign(draft, patch)
})
)
} catch {}
},
}),
}),
})
  1. Ketika Query updatePost di eksekusi, fungsi onQueryStarted akan ter-eksekusi.
  2. onQueryStarted akan mempassing parameter id dan patch (body dari mutasi).
  3. Dalam block try kita akan menunggu querFulfilled hingga data berhasil terupdate di sisi server.
  4. Setelah querFulfilled sudah tereksekusi, maka cache query getPost dengan id yang bersangkutan akan diupdate dengan object patch.
  5. Apabila terjadi error, dalam block catch tidak dilakukan action apa-apa.

Kesimpulan

Dengan menggunakan Teknik Optimistic atau Pessimistic Update, kita bisa lebih menghemat query ke Database, karena di sisi FE call API yang di lakukan menjadi lebih sedikit. Tentu saja tidak semua case cocok menggunakan kedua teknik caching ini. Teknik Optimistic & Pessimistic Update akan cocok apabila diterapkan pada data tunggal.

Data tunggal yang dimaksud di sini adalah data object tunggal yang hanya bisa di mutasi oleh satu user saja. Misalkan seperti biodata user. Berbeda dengan data majemuk yang mana bisa di mutasi oleh beberapa user serta berbentuk list, jenis data ini lebih bagus di revalidate mengunakan cache tags biasa supaya selalu mendapatkan data terupdate dari server.

--

--