Pendahuluan
Membuat sebuah aplikasi tidak hanya sebatas dapat membuatnya bekerja sesuai yang kita inginkan, melainkan juga memikirkan kemungkinan perubahan dan penambahan fitur dari aplikasi tersebut. Nah, apa jadinya, jika aplikasi kamu sudah cukup kompleks dan beberapa bulan kemudian kamu ingin melakukan perubahan, tapi justru membuatmu kebingungan?
Kadang kita mengenal lelucon, "Ketika codingan yang kita buat, hanya kita dan dan Tuhan yang tahu. Dan setelah beberapa saat, hanya Tuhan saja yang tahu.".
Salah satu fitur lainnya dari Vuex, selain memudahkan kamu dalam manajemen state agar dapat digunakan oleh semua component yang berperan, juga memungkinkan kamu untuk memecah block code yang telah dibuat kedalam Module sesuai dengan peruntukannya masing-masing. Misalnya, kita memiliki 3 buah fitur, yakni: Donatur, Client dan Transaksi. Jika ketiga code untuk meng-handle fitur tersebut disatukan dalam satu buah file, maka mengelolanya akan sangat membingungkan dikemudian hari. Bagaimana tidak? Jika code dari masing-masing fitur saling tercampur baur satu sama lain.
Baca Juga: Tutorial Vuex #1: Manajemen State
Tahap Persiapan
Meskipun artikel ini merupakan lanjutan dari seri sebelumnya, tapi kita akan memulainya dengan case yang berbeda, yakni: membuat aplikasi donasi. Buat project fresh install terlebih dahulu:
vue create donasi
Kemudian install library Vuex
npm install vuex --save
Kita akan membuat 3 buah component, yakni: Donatur.vue (untuk meng-handle list donatur), Clients.Vue (untuk meng-handle jenis bantuan) dan Transaksi.vue (untuk mencatat transaksi donasi yang telah dilakukan). Adapun hasil yang akan kita capai adalah sebagai berikut:
Buat file Donatur.vue
didalam folder src/components
:
<template>
<div>
<div class="form-group">
<label for="">Donatur</label>
<select @change="$emit('selectedDonatur', $event.target.value)" class="form-control">
<option value="">Pilih Donatur</option>
<option v-for="donatur in listDonatur" :key="donatur.id" :value="donatur.id">
{{ donatur.name }}
</option>
</select>
</div>
</div>
</template>
<script>
export default {
computed: {
//MEMBUAT COMPUTED PROPERTY DENGAN NAMA listDonatur()
listDonatur() {
//DATA DIAMBIL DARI STATE MODULE donatur
return this.$store.state.donatur.listDonatur
}
}
}
</script>
Penjelasan: Yang perlu diperhatikan adalah computed property yang ada, dimana data tersebut berasal dari module Vuex yang bernama donatur
. Selanjutnya module ini akan kita buat pada sub topik selanjutnya. So, cara mengambil data state
dari Vuex adalah this.$store.state
kemudian diikuti dengan nama state (jika tidak didalam module) atau dengan nama module kemudian nama state (jika state tersebut berada didalam module).
Component kedua adalah Clients.vue
, tempatkan didalam folder src/components
:
<template>
<div>
<div class="form-group">
<label for="">Jenis Bantuan</label>
<select @change="$emit('selectedBantuan', $event.target.value)" class="form-control">
<option value="">Pilih Bantuan</option>
<option v-for="row in listBantuan" :key="row.id" :value="row.id">
{{ row.name }}
</option>
</select>
</div>
</div>
</template>
<script>
export default {
computed: {
listBantuan() {
return this.$store.state.clients.listBantuan
}
}
}
</script>
Note: Metode yang digunakan sama dengan component sebelumnya.
Component trakhir adalah Transaksi.vue
, letakkan didalam folder yang sama dengan component sebelumnya:
<template>
<div class="table-responsive">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>#</th>
<th>Donatur</th>
<th>Jenis Bantuan</th>
<th>Jumlah</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</template>
<script>
export default {
computed: {
}
}
</script>
Note: Computed property sengaja kita kosongkan, karena akan menggunakan pemanggilan state
dengan helpers.
Buka file public/index.html
, kemudian tambahkan cdn Bootstrap karena kita akan menggunakan style dari Bootstrap:
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
Buka file src/App.vue
, kemudian modifikasi menjadi:
<template>
<div id="app">
<div class="container" style="padding-top: 20px">
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h3 class="card-title">Form Donasi</h3>
</div>
<div class="card-body">
<list-donatur @selectedDonatur="selectedDonatur" />
<lokasi-bencana @selectedBantuan="selectedBantuan" />
<div class="form-group">
<label for="">Jumlah Donasi (Rp)</label>
<input type="number" v-model="jumlah" class="form-control">
</div>
<div class="form-group">
<button class="btn btn-primary btn-sm"
@click="submitDonasi"
:disabled="isLoading">
{{ isLoading ? 'Loading...':'Donasi!' }}
</button>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h3 class="card-title">Donasi Terkumpul</h3>
</div>
<div class="card-body">
<list-transaksi />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Donatur from './components/Donatur.vue'
import Clients from './components/Clients.vue'
import Transaksi from './components/Transaksi.vue'
export default {
data() {
return {
donatur: '',
clients: '',
jumlah: 0
}
},
computed: {
isLoading() {
//MENGAMBIL STATE DARI ROOT VUEX (store.js)
//JADI, SETELAH .state. LANGSUNG MENYEBUTKAN NAMA STATENYA
//KARENA TIDAK MASUK KEDALAM MODULE
return this.$store.state.isLoading
}
},
methods: {
//HANDLE EMIT DARI COMPONENT DONATUR
selectedDonatur(val) {
this.donatur = val
},
//HANDLE EMIT DARI COMPONENT CLIENTS
selectedBantuan(val) {
this.clients = val
},
submitDonasi() {
//AKAN KITA MODIFIKASI SELANJUTNYA
}
},
components: {
'list-donatur': Donatur,
'lokasi-bencana': Clients,
'list-transaksi': Transaksi
}
}
</script>
Note: Ketiga component tersebut kita import untuk digunakan pada form yang telah disediakan. Untuk penjelasan masing-masing methods yang terakait sudah saya sematkan didalam coding diatas.
Buat file store.js
didalam folder src
kemudian tambahkan code berikut:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
isLoading: false
},
modules: {
// MODULE AKAN DITEMPATKAN DISINI
}
})
Terakhir buka file main.js
, kemudian modifikasi menjadi:
import Vue from 'vue'
import App from './App.vue'
import store from './store' //IMPORT STORE.JS
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store // USE store
}).$mount('#app')
Baca Juga: Tutorial Vuex #2: Mutations & Actions
Membuat Module Vuex & Menggunakan Helpers
Module memungkinkan kita untuk memecah bagian dari aplikasi kita agar dapat di-handle dengan mudah, sebab apabila digabungkan dalam satu file akan membentuk kumpulan code yang cukup besar dan menyulitkan kita untuk mencari bagian bagian yang akan dimodifikasi kemudian hari.
Buat sebuah folder dengan nama modules
(baca: nama folder boleh beda, bebas.) didalam folder src
untuk menampung file module yang akan dibuat selanjutnya. Terdapat 3 buah component, dimana masing-masing component ini pada case kali ini akan kita kelompokkan menjadi 3 buah modules juga, yakni: donatur, clients dan transaksi.
Pertama, buat file donatur.js
didalam folder src/modules
, kemudian masukkan code berikut:
const donatur = {
namespaced: true,
state: {
listDonatur: [
{ name: 'Riski Amelia' },
{ name: 'Ima Sumadir' },
{ name: 'Apri Yunita' },
{ name: 'Tuti Winarti' }
]
},
mutations: {
// NONE
},
actions: {
// NONE
}
}
export default donatur
Penjelasan: Terdapat sebuah state listDonatur
yang memiliki data default sebanyak 4 buah object. Dimana data ini akan ditampilkan pada component Donatur.vue
yang telah dibuat sebelumnya.
File berikutnya adalah client.js
yang diletakkan didalam folder src/modules
, kemudian tambahkan code berikut:
const clients = {
namespaced: true,
state: {
listBantuan: [
{ name: 'Gempa Lombok', },
{ name: 'Beasiswa Pendidikan' },
{ name: 'Banjir Bandang' },
{ name: 'Tanggungan Kesehatan' }
]
},
mutations: {
// NONE
},
actions: {
// NONE
}
}
export default clients
Note: Kegunaannya sama dengan module sebelumnya.
Terakhir, buat file transaksi.js
didalam folder src/modules
:
const transaksi = {
namespaced: true,
state: {
//DEFAULT DATA TRANSAKSI YANG AKAN DITAMPILKAN
//PADA COMPONENT TRANSAKSI.VUE
listTransaksi: [
{ id: 'TRX1P1', donatur: 'Anugrah Sandi', bantuan: 'Gempa Lombok', jumlah: 100000 },
{ id: 'TRX1P2', donatur: 'Dharma', bantuan: 'Banjir Bandang', jumlah: 250000 },
{ id: 'TRX1P3', donatur: 'Asis Ramadhan', bantuan: 'Beasiswa Pendidikan', jumlah: 3000000 }
]
},
mutations: {
//MENGUBAH STATE DENGAN
ADD_DONASI: (state, payload) => {
//MENAMBAHKAN DATA BARU KEDALAM ARRAY MENGGUNAKAN PUSH()
state.listTransaksi.push(payload)
}
},
actions: {
save_donasi({ commit, rootState }, payload) {
// rootState BERARTI MENGAKSES STATE YANG TIDAK BERADA DALAM MODULES
// DALAM HAL INI STATE isLoading YANG ADA DI DALAM FILE store.js
rootState.isLoading = true //SET TRUE UNTUK MEMBERIKAN EFEK LOADING
setTimeout(() => {
//MENGINSTRUKSIKAN PADA MUTATIONS TERKAIT UNTUK MENJALANKAN INSTRUKSINYA
commit('ADD_DONASI', payload)
// STATE isLoading DI MATIKAN KEMBALI
rootState.isLoading = false
}, 1000)
}
}
}
export default transaksi
Agar ketiga modules tersebut dapat digunakan, maka kita harus mendefinisikannya pada root Vuex, dalam hal ini file store.js
, buka file tersebut kemudian modifikasi menjadi:
import Vue from 'vue'
import Vuex from 'vuex'
//IMPORT KETIGA MODULES
import donatur from './modules/donatur'
import clients from './modules/clients'
import transaksi from './modules/transaksi'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
isLoading: false
},
modules: {
//DEFINISIKAN KETIGA MODULE TERSEBUT
donatur,
clients,
transaksi
}
})
Pada form input donasi kita memiliki sebuah tombol yang memicu methods submitDonasi()
ketika di-klik. Dimana methods tersebut masih kita biarkan kosong pada sub topik sebelumnya. So, buka file App.vue
kemudian modifikasi methods tersebut menjadi:
submitDonasi() {
// dispatch BERARTI MEMANGGIL FUNGSI YANG ADA DI ACTION
// DIMANA FUNGSI TERSEBUT BERNAMA save_donasi
// DAN BERADA DIDALAM MODULE transaksi
// JADI CARA MEMANGGILNYA ADALAH namamodule/namafungsi
this.$store.dispatch('transaksi/save_donasi', {
//MENGIRIM 4 BUAH PARAMETER YANG AKAN DIPUSH KEDALAM LISTS ARRAY listTransaksi
id: Math.random().toString(36).substring(7),
donatur: this.donatur,
bantuan: this.clients,
jumlah: this.jumlah
})
}
Sampai pada tahap ini kita sudah berhasilkan membuat form untuk menambahkan data baru kedalam array listTransaksi
untuk menampung data tersebut. Akan tetapi, listTransaksi belum dapat digunakan oleh component Transaksi.vue
karena data tersebut belum didefinisikan pada component terkait.
Yap! Kita akan menggunakan computed property untuk menggunakan state dari module transaksi. Hanya saja, jika dua component lainnya yakni: Donatur.vue
dan Client.vue
menggunakan cara this.$store.state.namamodule.namastate
, maka pada component Transaksi.vue
akan menggunakan helpers mapState
.
Buka file Transaksi.vue
, kemudian modifikasi menjadi:
<template>
<div class="table-responsive">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>#</th>
<th>Donatur</th>
<th>Jenis Bantuan</th>
<th>Jumlah</th>
</tr>
</thead>
<tbody>
<!-- LOOPING LIST ARRAY DARI listTransaksi -->
<tr v-for="(row, index) in listTransaksi" :key="index">
<td>{{ index+1 }}</td>
<td>{{ row.donatur }}</td>
<td>{{ row.bantuan }}</td>
<td>{{ row.jumlah }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { mapState } from 'vuex' //IMPORT mapState
export default {
computed: {
//MENGGUNAKAN HELPER mapState UNTUK MEMANGGIL MODULE transaksi
...mapState('transaksi', {
// DIMANA DATA YANG AKAN DIAMBIL ADALAH STATE listTransaksi
listTransaksi: state => state.listTransaksi
})
}
}
</script>
Sampai pada tahap ini, aplikasi yang kita inginkan sudah berjalan sebagaimana mestinya. Jalankan command npm run serve
.
Sebagai tambahan karena tidak sempat digunakan pada codingan diatas, maka untuk penggunaan helpers mapActions
dapat kamu lakukan dengan cara:
methods: {
...mapActions('namamodule', ['namafungsi']), //HELPERS ACTIONS YANG BERADA DALAM MODULE
...mapActions(['namafungsi']), //HELPERS ACTION YANG TIDAK BERADA DALAM MODULE
simpan() {
this.namafungsi() //CARA MENGGUNAKAN ACTIONS YANG SUDAH DIPANGGIL MELALUI HELPERS
}
}
Kesimpulan
Vuex memungkin codingan yang kamu menjadi lebih terstruktur sehinga lebih mudah dalam mengelolanya baik saat proses development maupun ketika ada pengembangan dikemudian hari. Lengkap sudah ketiga seri ini sebagai modal dasar dalam memahami bagaimana cara menggunakan Vuex.
Bermodalkan pemahaman bagaimana cara mendefinisikan state, mutations, dan action serta cara menggunakan ketiganya baik didalam modules maupun tidak, sudah menjadi modal yang cukup kuat untuk diimplementasikan pada project yang sedang kamu kerjakan. Seiringin berjalannya waktu kamu akan menemukan best practice dalam menggunakan Vuex.
Dokumentasi dari code diatas dapat kamu lihat di Github.
Comments