GithubHelp home page GithubHelp logo

education-intermediate-vue3-pinia's Introduction

Pinia in a Nutshell

Persyaratan

  • Sudah mengerti dan menggunakan create-vue
  • Mengerti dasar Vue 3 (Options API)
  • Mengerti dasar penggunaan CSS (pada pembelajaran ini menggunakan tailwind)

What is Pinia ?

Dikutip dari situs Pinia, Pinia ini adalah Vue Store yang menyenangkan untuk digunakan.

Lebih detilnya, Pinia ini adalah library untuk Store di dalam Vue, yang membuat si developer dapat nge-share suatu state ke dalam suatu Components / Pages.

Masih bingung? Mari kita coba dengan bahasa yang lebih manusiawi lagi.

Pinia adalah suatu library untuk me-manage state pada Vue.

Anggap saja Pinia sebagai sebuah "wadah" untuk menyimpan data secara global pada Vue, sehingga kita tidak perlu menaruh data global pada App.vue atau pada Component Utama lagi DAN kita tidak perlu lagi untuk mem-passing data terlalu dalam / melakukan props terlalu banyak a.k.a props drilling.

Sudah mulai terdengar seru? mari kita coba install Pinia sekarang yah !

How to Install Pinia ?

Untungnya Pinia ini sudah diincludekan di dalam template bawaan dari create-vue, sehingga cara instalasinya pun menjadi cukup mudah:

  1. Menggunakan perintah npm init vue@latest
  2. Masukkan project name yang diinginkan
  3. Pilih opsi untuk menggunakan Typescript atau tidak (pada pembelajaran ini No)
  4. Pilih opsi untuk menggunakan JSX atau tidak (pada pembelajaran ini No)
  5. Pilih opsi untuk menggunakan Vue Router atau tidak (pada pembelajaran ini Yes)
  6. Pilih opsi untuk menggunakan Pinia atau tidak (tentunya YES)
  7. Pilih opsi untuk menggunakan Vitest atau tidak (pada pembelajaran ini No)
  8. Pilih opsi untuk menggunakan Cypress atau tidak (pada pembelajaran ini No)
  9. Pilih opsi untuk menggunakan ESLint atau tidak (pada pembelajaran ini Yes)
  10. Pilih opsi untuk menggunakan Prettier atau tidak (pada pembelajaran ini Yes)

Sampai di tahap ini artinya initial project untuk Vue yang menggunakan Pinia sudah berhasil dibuat, selanjutnya kita akan memasang dan menjalankan starter pack dengan cara:

  1. Menggunakan perintah cd nama_project_yang_dibuat
  2. Menginstall package yang dibutuhkan dengan perintah npm install
  3. Menjalankan project dengan perintah npm run dev

Dan kita bisa melihat starter pack yang disediakan pada http://localhost:5173 (port default Vite)

Selanjutnya kita akan belajar bagaimana cara menggunakan Pinia

How to Pinia

Di dalam Pinia ini, akan ada beberapa istilah baru yang harus kita pelajari, yaitu:

  • Store
  • State
  • Actions
  • Getters
  • Plugins

Store

Sesuai namanya, Store ini adalah tempat di mana kita meletakkan keseluruhan kode yang mengandung global state management di dalam Pinia ini.

WARNING:

  • Hati hati terhadap id yang harus digunakan di dalam store ini. HARUS bersifat unik !

Mari buka file src/stores/counter.js untuk penjelasan lebih lanjut

defineStore({
  id: 'counter',
  ...
})

Perhatikan id counter, ini harus bersifat untuk dan tidak boleh sama antar store satu dengan store lainnya (bila nantinya ingin memecah store menjadi banyak).

State

State merupakan core dari Pinia ini, adalah data global yang disimpan pada Pinia yang nantinya akan digunakan oleh Component / Pages manapun di dalam Vue.

Ingat kata magicnya: MANAPUN

Actions

Actions ini anggapannya seperti methods yang ada pada Vue "normal" yang digunakan dan boleh bersifat synchronous ataupun asynchronous.

Artinya di actions ini, kita bisa mendefinisikan methods yang butuh melakukan proses dengan waktu yang tidak tentu seperti:

  • Fetching data ...
  • Fetching data
  • FETCHING DATA !

Dan nantinya Actions ini juga bisa langsung di-teleport-kan ke dalam Component / Pages yang membutuhkan.

Oh ya, di dalam Actions ini pun, kita bisa mendefinisikan logic untuk mengubah State yang ada di dalam Store, mantap kan?

Getters

Getters, sesuai namanya, ini merupakan Getter (pengambil) State. Loh kenapa harus ada ini, padahal kan State boleh diambil secara langsung?

Anggap saja Getters ini adalah computed yang ada pada Vue, yaitu membaca state dan mengembalikan data hasil komputasinya.

mis, dari data State yang merupakan Array of Object, kita ingin memfilter sesuatu berdasarkan id nya, atau kata kunci lainnya, maka kita bisa menggunakan Getter untuk hal tersebut ๐Ÿ˜

Pada pembelajaran ini tidak didemokan yah !

Let's Get Started with Pinia !

Yuk yuk sudah cukup teorinya, mari sekarang kita akan mulai untuk menggunakan Pinia ke dalam aplikasi kita yah !

Pada pembelajaran ini kita akan membuat sebuah aplikasi berbasis Pinia yang memiliki beberapa fitur utama:

  • Sebuah button yang berfungsi untuk menambahkan suatu angka, yang dibuat dalam 2 component yang berbeda (Kiri: button, kanan: tampilan hasil penambahan angka)
  • Sebuah form dan hasil panggilan formnya, dibuat dalam 2 component yang berbeda juga. (Kiri: Form, Kanan, tampilan hasil form setelah disubmit)
  • Sebuah tabel yang akan menampilkan list jokes dari situs https://v2.jokeapi.dev/, terdiri dari 2 component berupa TableList yang didalamnya terdapat component TableContent.

Keseluruhan aplikasi ini akhirnya akan memanfaatkan Pinia yah !

Bagaimanakah Caranya?

  1. Menggunakan perintah npm init vue@latest untuk membuat project awal Vue yang menggunakan Vue Router dan Pinia
  2. Karena pada pembelajaran ini menggunakan tailwind, maka di sini juga menggunakan tutorial tambahan dari situs Tailwind secara langsung yang dapat dilihat di sini untuk menginstall tailwind css
  3. Selanjutnya karena pembelajaran ini juga menggunakan fetcher data axios, tambahkan package axios dengan menggunakan perintah npm install axios

Langkah Nol - Membuat Template

Ya ! Pada pembelajaran ini, templatenya akan kita buat sendiri yah (tenang, dipandu untuk kode-nya kok supaya tidak berbusa otak dan mulutnya ๐Ÿ˜)

  1. Membuat beberapa components (pada folder src/components) dengan nama seperti di bawah ini:
    • IncrementalLeft.vue
    • IncrementalRight.vue
    • FormLeft.vue
    • FormRight.vue
    • TableList.vue
    • TableContent.vue
  2. Memodifikasi File IncrementalLeft.vue sebagai berikut:
    <script>
    export default {
      name: "IncrementalLeft",
    };
    </script>
    
    <template>
      <button
        class="bg-gray-100 py-2 px-4 rounded-md hover:bg-gray-300 hover:shadow-md"
      >
        Increment
      </button>
    </template>
    
    <style scoped></style>
  3. Memodifikasi File IncrementalRight.vue sebagai berikut:
    <script>
    export default {
      name: "IncrementalRight",
    };
    </script>
    
    <template>
      <div>
        <p class="font-semibold">0</p>
      </div>
    </template>
    
    <style scoped></style>
  4. Memodifikasi File FormLeft.vue sebagai berikut:
    <script>
    export default {
      name: "FormLeft",
    };
    </script>
    
    <template>
      <form action="#">
        <div>
          <input
            type="text"
            placeholder="Just write me"
            class="shadow appearance-none border rounded py-2 px-3 text-gray-700"
          />
        </div>
        <div class="mt-4">
          <button
            type="submit"
            class="bg-gray-100 py-2 px-4 rounded-md hover:bg-gray-300 hover:shadow-md"
          >
            Transfer Me
          </button>
        </div>
      </form>
    </template>
    
    <style scoped></style>
  5. Memodifikasi File FormRight.vue sebagai berikut:
    <script>
    export default {
      name: "FormRight",
    };
    </script>
    
    <template>
      <div>
        <p class="font-semibold">Placeholder for the Form Value</p>
      </div>
    </template>
    
    <style scoped></style>
  6. Memodifikasi File TableList.vue sebagai berikut:
    <script>
    import TableContent from "./TableContent.vue";
    export default {
      components: { TableContent },
      name: "TableList",
    };
    </script>
    
    <template>
      <table class="table-fixed w-full border-collapse border border-gray-300">
        <thead>
          <tr class="bg-gray-100">
            <th class="w-1/6 border border-gray-300">ID</th>
            <th class="w-1/3 border border-gray-300">Setup</th>
            <th class="w-1/3 border border-gray-300">Punchline</th>
          </tr>
        </thead>
        <table-content></table-content>
      </table>
    </template>
    
    <style scoped></style>
  7. Memodifikasi File TableContent.vue sebagai berikut:
    <script>
    export default {
      name: "TableContent",
    };
    </script>
    
    <template>
      <tbody>
        <tr>
          <td class="border border-gray-300">Placeholder ID</td>
          <td class="border border-gray-300">Placeholder Setup</td>
          <td class="border border-gray-300">Placeholder Punchline</td>
        </tr>
      </tbody>
    </template>
    
    <style scoped></style>
  8. Memodifikasi File src/views/AboutView.vue sebagai berikut:
    <script>
    import FormLeft from "../components/FormLeft.vue";
    import FormRight from "../components/FormRight.vue";
    import IncrementalLeft from "../components/IncrementalLeft.vue";
    import IncrementalRight from "../components/IncrementalRight.vue";
    import TableList from "../components/TableList.vue";
    
    export default {
      components: {
        IncrementalLeft,
        IncrementalRight,
        FormLeft,
        FormRight,
        TableList,
      },
    };
    </script>
    
    <template>
      <div class="bg-gray-200 text-gray-700 p-4">
        <div class="container flex flex-col mx-auto">
          <!-- Incremental Section -->
          <div class="mx-auto py-4">
            <h3 class="font-bold">Incremental Section</h3>
          </div>
          <div class="flex flex-row mx-auto py-4">
            <incremental-left class="mr-4"></incremental-left>
            <incremental-right class="ml-4 my-auto"></incremental-right>
          </div>
          <!-- Form Section -->
          <div class="mx-auto py-4">
            <h3 class="font-bold">Form Section</h3>
          </div>
          <div class="flex flex-row mx-auto py-4">
            <form-left class="mr-4"></form-left>
            <form-right class="ml-4 my-auto"></form-right>
          </div>
          <!-- Table Section -->
          <div class="mx-auto py-4">
            <h3 class="font-bold">Table Section</h3>
          </div>
          <div class="mx-auto">
            <table-list></table-list>
          </div>
        </div>
      </div>
    </template>
    
    <style scoped></style>

Sampai pada tahap ini artinya kita sudah membuat seluruh template yang digunakan untuk pembelajaran ini dan kita siap untuk masuk ke dalam pembuatan kode dengan Pinia !

Langkah Pertama - Incremental Section

Pada langkah ini kita akan menyelesaikan logika untuk Incremental pada component IncrementalLeft dan IncrementalRight.

Ketika button pada IncrementalLeft ditekan, akan menambahkan angka yang ada pada IncrementalRight sebesar 10000.

Sekarang untuk bisa menyelesaikan permasalahan ini, kita akan membutuhkan sebuah state pada store agar dapat digunakan di component yang akan digunakan.

Langkah pengerjaannya adalah sebagai berikut:

  1. Membuat sebuah stores yang baru dengan nama src/stores/custom.js
  2. Memodifikasi kode pada src/stores/custom.js sebagai berikut:
    // import defineStore dari pinia
    import { defineStore } from "pinia";
    
    // export store yang dibuat agar dapat digunakan
    // defineStore adalah sebuah fungsi yang menerima options
    export const customStore = defineStore({
      // salah satu options-nya wajib ada 'id'
      id: "custom",
      // di sini kita akan declare state yang ada di dalam store ini
      // state adalah sebuah fungsi (disarankan dengan arrow function)
      // fungsi ini akan mereturn sebuah object (mirip data pada component vue)
      state: () => ({
        // declare state yang dibutuhkan
        initialNumber: 10,
      }),
    });
  3. Selanjutnya kita akan menyambungkan state yang ada pada src/stores/custom.js ini pada component IncrementalRight.vue, namun dimanakah kita menaruh state initialNumber ini? Karena data ini bisa berubah terus menerus, maka tentunya kita tidak bisa menaruh state yang ada di stores ini di dalam data, tapi kita harus menaruhnya di dalam ... computed !
  4. Cara untuk meletakkannya adalah dengan membaca dokumentasi pinia state dapat dilihat di sini).
  5. Memodifikasi file IncrementalRight.vue sebagai berikut:
    <script>
    // import mapState dari pinia
    import { mapState } from "pinia";
    // import store yang digunakan
    import { customStore } from "../stores/custom";
    
    export default {
      name: "IncrementalRight",
      // state dari pinia akan kita letakkan pada "computed"
      // yang ada di component
      computed: {
        // gunakan spread agar bisa dikombinasikan dengan computed
        // pada local component ini.
    
        // mapState menerima 2 parameter:
        // parameter 1 adalah store yang digunakan
        // parameter 2 adalah array of string dari state yang ingin
        //    igunakan dari store
        ...mapState(customStore, ["initialNumber"]),
      },
    };
    </script>
    
    <template>
      <div>
        <p class="font-semibold">
          <!-- di sini kita akan menggunakan computed-nya -->
          {{ initialNumber }}
        </p>
      </div>
    </template>
    
    <style scoped></style>
  6. Dan voila !, kita sudah berhasil untuk membaca data state dan menaruhnya pada component IncrementalRight.vue ini !
  7. Selanjutnya kita akan mencoba untuk membuat fungsi untuk menambahkan state ketika tombol yang ada pada IncrementalLeft.vue ini ditekan. Untuk itu, sekarang kita harus memodifikasi src/stores/custom.js untuk membuat fungsi tersebut. Fungsi ini akan kita buat pada bagian actions yang ada pada stores, dan modifikasi kodenya adalah sebagai berikut:
    import { defineStore } from "pinia";
    
    export const customStore = defineStore({
      id: "custom",
      state: () => ({
        initialNumber: 10,
      }),
      // di sini kita akan declare sebuah fungsi (methods) yang akan menambahkan initialNumber sebesar 10000
      // dengan menggunakan "actions".
      // anggap ini seperti "methods" pada component Vue
      actions: {
        // di sini kita akan membuat method-nya
    
        // karena ini akan mengubah state secara langsung
        // maka kita tidak membutuhkan `async`
        incrementInitialNumber() {
          // untuk akses state tinggal menggunakan "this"
          this.initialNumber += 10000;
        },
      },
    });
  8. Selanjutnya kita tinggal menggunakan actions yang sudah kita buat ini pada IncrementalLeft.vue. Memodifikasi IncrementalLeft.vue sebagai berikut:
    <script>
    // di sini kita akan import mapActions
    import { mapActions } from "pinia";
    // jangan lupa import store yang digunakan
    import { customStore } from "../stores/custom";
    
    export default {
      name: "IncrementalLeft",
      // actions akan kita letakkan pada.... methods !
      methods: {
        // gunakan spread seperti mapState
        ...mapActions(customStore, ["incrementInitialNumber"]),
        // kita coba juga membuat local methodsnya
        buttonOnClickHandler() {
          console.log("Tombol tertekan");
          // invoke actions
          this.incrementInitialNumber();
        },
      },
    };
    </script>
    
    <template>
      <!-- Sambungkan event onclick dengan methods buttonOnClickHandler -->
      <button
        class="bg-gray-100 py-2 px-4 rounded-md hover:bg-gray-300 hover:shadow-md"
        v-on:click="buttonOnClickHandler"
      >
        Increment
      </button>
    </template>
    
    <style scoped></style>

Sampai pada tahap ini artinya kita sudah berhasil menggunakan state dan actions dari Pinia pada 2 component yang terpisah, IncrementalLeft.vue dan IncrementalRight.vue.

Cukup menakjubkan bukan? Langsung nyambung loh, padahal adanya di store

Langkah Kedua - Form Section

Pada bagian ini kita akan mencoba untuk menyelesaikan bagian Form, dimana pada saat form yang ada pada FormLeft ini di-submit, maka akan memengaruhi konten yang ditampilkan pada FormRight.

Langkah-langkah pengerjaannya adalah sebagai berikut:

  1. Memodifikasi file src/stores/custom.js untuk menambahkan sebuah state baru dengan nama formData dan sebuah actions untuk mengubah formData bernama formHandler, kode modifikasinya adalah sebagai berikut:
    import { defineStore } from "pinia";
    
    export const customStore = defineStore({
      id: "custom",
      state: () => ({
        initialNumber: 10,
        // declare state untuk handle form
        formData: {
          // karena bisa banyak valuenya, kita bentuk dalam object
          value1: "Placeholder",
        },
      }),
      actions: {
        incrementInitialNumber() {
          this.initialNumber += 10000;
        },
    
        // method Actions untuk menghandle Form
        // karena sekarang di sini kita membutuhkan input
        // maka kita bisa menggunakan parameter di dalam fungsi
        // yang dibuat
    
        // sebut saja nama parameternya adalah "payload"
        formHandler(payload) {
          // di sini kita akan mengubah keseluruhan dari formData
          this.formData = payload;
        },
      },
    });
  2. Selanjutnya kita akan menggunakan state formData.value1 pada component FormRight.vue. Memodifikasi FormRight.vue sehingga menjadi seperti ini:
    <script>
    // import mapState
    import { mapState } from "pinia";
    // import store
    import { customStore } from "../stores/custom";
    
    export default {
      name: "FormRight",
      // state pada pinia = computed di component
      computed: {
        ...mapState(customStore, ["formData"]),
      },
    };
    </script>
    
    <template>
      <div>
        <!-- di sini kita akan membaca formData.value1 -->
        <p class="font-semibold">{{ formData.value1 }}</p>
      </div>
    </template>
    
    <style scoped></style>
  3. Selanjutnya kita akan menggunakan actions formHandler pada component FormLeft.vue. Memodifikasi FormLeft.vue sehingga menjadi seperti ini:
    <script>
    // import mapActions
    import { mapActions } from "pinia";
    // import store
    import { customStore } from "../stores/custom";
    
    export default {
      name: "FormLeft",
      // karena di sini ada menggunakan form
      // maka sekarang kita juga membutuhkan local state
      data() {
        return {
          // sebut saja namanya adalah localFormData
          // karena kemungkinan ada banyak, kita bentuk dalam object
          localFormData: {
            input1: "",
          },
        };
      },
    
      // gunakan actions pada methods
      methods: {
        ...mapActions(customStore, ["formHandler"]),
        // tambahkan local methods untuk memproses form submission
        localFormHandler() {
          // di sinilah kita akan menggunakan actions
          // ingat formHandler menerima sebuah "payload" bukan?
          // bagaimana cara kita mengirimnya?
    
          // ya, lewat invoke dan kirim via args nya !
          // ingat payload menerima object primitif yah !
          this.formHandler({
            // ingat object nya menerima sebuah props dengan nama "value1" yah
            // lihat src/stores/custom.js pada state "formData" bila lupa
            value1: this.localFormData.input1,
          });
        },
      },
    };
    </script>
    
    <template>
      <!-- binding event localFormHandler pada form submission event  -->
      <form action="#" v-on:submit.prevent="localFormHandler">
        <div>
          <!-- jangan lupa binding 2 arah input ini dengan local data (v-model) -->
          <input
            type="text"
            placeholder="Just write me"
            v-model="localFormData.input1"
            class="shadow appearance-none border rounded py-2 px-3 text-gray-700"
          />
        </div>
        <div class="mt-4">
          <button
            type="submit"
            class="bg-gray-100 py-2 px-4 rounded-md hover:bg-gray-300 hover:shadow-md"
          >
            Transfer Me
          </button>
        </div>
      </form>
    </template>
    
    <style scoped></style>

Sampai pada tahap ini artinya kita sudah berhasil untuk membuat sebuah form submission yang mana akan langsung mengubah state dan perubahan dari state tersebut akan mengubah tulisan yang ada pada komponen lainnya secara langsung.

Asik kan Pinia?

Selanjutnya kita akan mulai bermain dengan tarikan data !

Langkah Ketiga - Table Section

Pada bagian ini kita akan mencoba untuk menyelesaikan bagian pada Table, dimana table ini akan menampilkan data dari eksternal (Jokes API), kemudian akan ditampilkan pada Tabel yang sudah kita buat sebelumnya.

Langkah-langkah pengerjaannya adalah sebagai berikut:

  1. Menyiapkan data provider berupa axios instance terlebih dahulu. Membuat folder /src/apis dan membuat sebuah file dengan nama jokes.js
  2. Memodifikasi kode pada /src/apis/jokes.js sebagai berikut:
    // import axios
    import axios from "axios";
    
    // membuat instance axios berdasarkan api yang digunakan
    // https://v2.jokeapi.dev
    const instance = axios.create({
      baseURL: "https://v2.jokeapi.dev/",
      // apabila membutuhkan header authorization
      //  (bearer / token / basic)
      //  bisa diletakkan di sini
    });
    
    // jangan lupa diexport karena akan digunakan di tempat lainny
    export default instance;
  3. Membuat sebuah method untuk mengambil data dari instance yang sudah dibuat. Sebut saja nama method nya adalah fetchJokes, dan karena kita sedang menggunakan pinia, maka method ini akan kita letakkan pada actions yang ada pada store pinia (src/stores/custom.js, bagian props actions). Namun supaya ada data yang dapat disimpan juga, maka kita juga akan membutuhkan sebuah state untuk menampung data kembalian dari pengambilan data dari API ini (sebut saja namanya adalah sebuah state dengan nama jokes).
  4. Memodifikasi file src/stores/custom.js menjadi seperti berikut
    import { defineStore } from "pinia";
    // import instance axios di sini
    import jokesInstance from "../apis/jokes";
    
    export const customStore = defineStore({
      id: "custom",
      state: () => ({
        initialNumber: 10,
        formData: {
          value1: "Placeholder",
        },
        // declare state untuk berisi kumpulan dari jokes
        jokes: [],
      }),
      actions: {
        incrementInitialNumber() {
          this.initialNumber += 10000;
        },
    
        formHandler(payload) {
          this.formData = payload;
        },
    
        // method Actions untuk mengambil data dari API Jokes
        // karena di sini akan mengambil data, yang mana durasi
        // pengerjaannya tidak menentu, maka kita akan menggunakan
        // logicnya secara asynchronous
    
        // tambahkan kata kata async di depan actions yang dibuat
        async fetchJokes() {
          try {
            // kita ambil data dari jokes api
            const response = await jokesInstance.get(
              "/joke/Any?blacklistFlags=nsfw,religious,political,racist,sexist,explicit&type=twopart&amount=10"
            );
    
            // apabila berhasil mendapatkan response (dunia sempurna)
            // maka kita akan set state jokesnya
    
            // data jokes ada pada Object punya props jokes
            this.jokes = response.data.jokes;
          } catch (err) {
            // error sederhana dengan console log
            // bila dibutuhkan bisa menggunakan sebuah state error
            //    atau langsung memberikan toast / swal
            console.log(err.response);
          }
        },
      },
    });
  5. Selanjutnya kita akan menyambungkan logic yang sudah dibuat pada stores ini dengan component yang sudah dibuat, yaitu TableContent dan TableList
  6. Memodifikasi component TableList.vue untuk memanggil fungsi fetchJokes pada saat component ini ada (created)
    <script>
    // import mapActions
    import { mapActions } from "pinia";
    // import stores
    import { customStore } from "../stores/custom";
    import TableContent from "./TableContent.vue";
    export default {
      components: { TableContent },
      name: "TableList",
      // declare actions pada methods
      methods: {
        ...mapActions(customStore, ["fetchJokes"]),
      },
      // panggil methods pada created
      created() {
        this.fetchJokes();
      },
    };
    </script>
    
    <template>
      <table class="table-fixed w-full border-collapse border border-gray-300">
        <thead>
          <tr class="bg-gray-100">
            <th class="w-1/6 border border-gray-300">ID</th>
            <th class="w-1/3 border border-gray-300">Setup</th>
            <th class="w-1/3 border border-gray-300">Punchline</th>
          </tr>
        </thead>
        <table-content></table-content>
      </table>
    </template>
    
    <style scoped></style>
  7. Sampai pada titik ini, pada saat component TableList akan dirender, maka akan memanggil actions bernama fetchJokes dan akan mengubah state jokes. Namun jokes ini masih nganggur. Selanjutnya kita akan membaca state jokes ini dan menampilkannya pada TableContent. Ingat bahwa TableContent ini adalah data per baris, sehingga harus dilakukan looping.
  8. Memodifikasi file TableList.vue lagi untuk membaca state jokes:
    <script>
    // import mapActions dan mapState
    import { mapActions, mapState } from "pinia";
    import { customStore } from "../stores/custom";
    import TableContent from "./TableContent.vue";
    export default {
      components: { TableContent },
      name: "TableList",
     methods: {
        ...mapActions(customStore, ["fetchJokes"]),
      },
      // declare state pada computed
      computed: {
        ...mapState(customStore, ["jokes"]),
      },
      created() {
        this.fetchJokes();
      },
    };
    </script>
    
    <template>
      <table class="table-fixed w-full border-collapse border border-gray-300">
        <thead>
          <tr class="bg-gray-100">
            <th class="w-1/6 border border-gray-300">ID</th>
            <th class="w-1/3 border border-gray-300">Setup</th>
            <th class="w-1/3 border border-gray-300">Punchline</th>
          </tr>
        </thead>
        <!-- karena sekarang kita butuh looping -->
        <!-- Maka kita akan menggunkan v-for dan anggap state jokes seperti -->
        <!-- computed pada umumnya  -->
        <table-content
          v-for="joke in jokes"
          v-bind:key="joke.id"
          v-bind:jokeYangDilempar="joke"
        ></table-content>
      </table>
    </template>
    
    <style scoped></style>
  9. Perhatikan pada kode di atas, bahwa pada akhirnya kita menggunakan cara normal pada Vue (menggunakan v-bind custom attributes), yang mana artinya sekarang kita akan memodifikasi TableContent.vue untuk menerima custom attributes tersebut melalui ... props ! Memodifikasi kode TableContent.vue sebagai berikut:
    <script>
    export default {
      name: "TableContent",
      // menerima props
      props: ["jokeYangDilempar"],
    };
    </script>
    
    <template>
      <tbody>
        <tr>
          <!-- Kita gunakan props punya data di sini -->
          <td class="border border-gray-300">{{ jokeYangDilempar.id }}</td>
          <td class="border border-gray-300">{{ jokeYangDilempar.setup }}</td>
          <td class="border border-gray-300">{{ jokeYangDilempar.delivery }}</td>
        </tr>
      </tbody>
    </template>
    
    <style scoped></style>
  10. Lessons Learned: Jadi tidak pasti bahwa dengan menggunakan Pinia artinya kita benar benar 100% meninggalkan props yah ๐Ÿ˜Š, hanya penggunaannya jadi lebih berkurang !

Hint Pinia

  • Harus mengetahui kapan menggunakan state, action, dan getter
  • Ingat bahwa Pinia memiliki built in function untuk mempermudah hidup (mapXXX)
  • Untuk mengkombinasikan dengan router, bisa menggunakan markRaw (lihat referensi di bawah untuk markRaw)

References

education-intermediate-vue3-pinia's People

Contributors

withered-flowers avatar

Stargazers

Ghazy Prihanda avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.