Kode Terlalu Repetitif di Reducer? Introduce: Higher-Order Reducer
Salaam semuanya! Maaf udah lama ndak nulis lagi, diitung-itung udah 9 bulan vakuum. Entah kenapa semenjak nikah, rutinitas-rutinitas kayak nulis dan belajar-belajar jadi suka terbengkalai π You know lah wkwk. Sampai akhirnya disentil sama Shifu Irfan Maulana buat nulis lagi π *maafkan saya Shifu
So, balik ke topik. Higher-Order Reducer. Entah istilah ini tepat atau nggak, saya sendiri kurang begitu yakin, tapi saya akan coba terangkan secara singkat dimulai dari permasalahan yang sangat sangat simple: Async Actions.
The problem
Biasanya, Async Actions ini direpresentasikan dengan tambahan 3 suffix berikut: REQUEST, SUCCESS, dan FAILED.
const createAction = actionName => payload => ({
type: actionName,
payload
})const getUserRequest = createAction('GET_USER_REQUEST')
const getUserSuccess = createAction('GET_USER_SUCCESS')
const getUserFailed = createAction('GET_USER_FAILED')
Setelah berhasil mendapatkan datanya dari suatu endpoint, kita hanya ingin menyimpan datanya di redux store. Urusan pengolahan business logic bisa kita serahkan ke function lain (use reselect), saat ini kita hanya fokus pada penyimpanan datanya saja.
Kita bisa handle ketiga action creators ini di reducer seperti:
Sangat standar. Works good. Nothing special.
BUT. Bagimana jadinya kalo Async Action kita lebih dari satu? Bagaimana kalau kita ingin fetch post
juga? Solusi paling mudah: tinggal kopas aja dari user
dan ganti key-nya jadi post
π
Hmm, ada yang salah? Keliatannya sih baik-baik aja, tapi agak kurang sreg gimanaa gitu ya. I smell repetitive code, yang mungkin saja OK, tapi in most cases not OK. Karena bisa jadi, kita gak cuma akan fetch user
dan post
saja, mungkin kita juga mau fetch data-data lain dan menyimpan hasilnya di redux store. Jika hal itu dilakukan dengan metode copy-paste-modify seperti halnya di atas, konsekuensinya adalah longer repetitive code, WICIS gak baik.
(sengaja saya bold, biar keliatan pinter bahasa inggris π)
Less code === Less bug
Jadi, bagaimana solusinya?
Higher-Order Reducer
Sesuai namanya, Higher-Order Reducer adalah suatu reducer yang menerima dan/atau mengembalikan reducer lain. Singkat cerita, kita akan meng-extract bagian yang repetitif tersebut menjadi sebuah reducer. Reducer di dalam reducer. Sebagai glue-nya, kita bisa menggunakan combineReducer
dari redux
.
Tapi sebelum masuk ke bagian intinya, saya ingin sedikit mengubah fungsi createAction
dan menambahkan sebuah fungsi baru bernama createAsyncAction
agar solusi yang ditawarkan menjadi lebih menarik.
(Yha, function adalah sebuah Object di Javascript. Bisa dicoba dengan menjalankan function seperti layaknya mengakses sebuah object seperti: document.addEventListener.length
. Lihat apa yang akan terjadi, nomor 7 bikin kamu geleng-geleng kepala!)
Daaan sekarang ke intinya, setting up the reducer:
combineReducers
sebagai glue reducers
kitaPerbedaan mendasar dari HOR ini adalah, kita membuat satu reducer sendiri untuk masing-masing object (dalam hal ini user
dan post
). Dibandingkan solusi awal yang hanya mengambalikan 1 reducer (untuk 2 object), dengan solusi HOR ini kita mengembalikan 2 reducer sekaligus (1 reducer untuk 1 object).
Jika dianalogikan, struktur redux store pada solusi awal adalah
// redux store solusi awal
(state, action) => ({
user: { // <- PLAIN OBJECT
data: {}
asyncState: ...,
},
post: { // <- PLAIN OBJECT
data: {}
asyncState: ...,
},
...
})
Bandingkan dengan menggunakan HOR:
// redux store solusi HOR
(state, action) => ({
user: (ownState, action) => ({ // <- REDUCER
data: {}
asyncState: ...,
}),
post: (ownState, action) => ({ // <- REDUCER
data: {}
asyncState: ...,
}),
...
})
Yha, sangat sangat sederhana. Tapi terkadang untuk menciptakan sesuatu yang sederhana itu tidak mudah. Senada dengan ucapan Legenda Sepak Bola Barcelona, Johan Cruyff ketika mencetus taktik sepakbola tiki-taka:
Playing football is very simple, but playing simple football is the hardest thing there is β Johan Cruyff
atau Legenda Sinetron Kolosal Indosari ketika terbang dengan naga:
Coding is very simple, but finding simple solution with code is the hardest thing there is β Jihad D. Waspada
Penutup
Dengan memanfaatkan konsep Higher-Order Reducer, kita bisa mengeliminasi kode yang repetitif di reducer sembari tetap menjaga struktur redux store kita. Potensi kegunaan HOR ini sangat luas, bisa diterapkan di kasus-kasus yang lain. Saya pribadi menggunakan konsep HOR ini untuk pekerjaan yang berhubungan dengan Form.
Oh ya, createAsyncCreator
di atas, saya derive dari Project Typescript-FSA. Sangat merekomendasikan library ini karena Typescript nya maknyus. Integrasi ke berbagai side-effect library-nya juga cukup memadai. Bisa ke Saga, ke Observable, atau bahkan ke reducer itu sendiri. Cek aja ya π
Terkahir, semoga tulisan ini bisa bermanfaat. Dan doakan juga semoga saya bisa konsisten nulis di medium lagi π. Dan semoga yang jomblo segera dapet istri! Bye!