Skip to main content

มาทำความรู้จัก Vuex ORM กันดีกว่า

·3 mins

ผมเชื่อ Vue developer หลายๆคนคงจะเคยได้ใช้งาน Vuex กันอยู่บ้าง และผมก็เชื่อว่าหลายคนคงหงุดหงิดกับการที่ต้องมาคอยใช้ this.$store.dispatch() เพราะมันไม่สวยงามเลย แต่เราก็ต้องยอมแลกเพราะมันทำให้เราจัดการ state ของข้อมูลได้ แต่ปัญหาเหล่านี้จะหมดไปถ้าคุณได้ลองใช้ Vuex-ORM

Vuex-ORM คืออะไร #

Vuex ถือกำเนิดขึ้นมาเพื่อใช้จัดการกับ state ทั้งหลายใน app ของเราไม่ว่าจะเป็น store, action หรือ mutation ผมเป็นคนนึงที่ขาด Vuex ถ้าจะต้องทำ **Vue Application **แล้วต้องมาจัดการอะไรพวกนี้เองหรือไม่จัดการมันเลยปล่อยมันอยู่ตาม view หรือ component กระจัดกระจาย ตอนแก้ผมคงปวดหัวแน่นอน แต่ถึงแม้มันจะเทพอย่างไรก็ตาม มันก็ต้องแลกด้วยพิธีและขั้นตอนที่ก็จะทำ code มันดูยุบยับหน่อย โดยเฉพาะมือใหม่หลายคนแค่เริ่มใช้ก็งงแล้ว

Vuex-ORM จึงได้คลานตามกันออกมา โดยเราจะยังคงความเจ๋งของ Vuex ไว้แล้วเสริมด้วยความเป็น ORM

ORM: object-relational mapping

พอเสริมความเป็น ORM เข้ามาแล้วมันทำให้ code นั้นเขียนง่ายและอ่านง่าย มอง object ที่เข้ามาใน store ให้เป็น Model สามารถทำ CRUD ได้เหมือน database โดยไม่ต้องเขียน code เพิ่มด้วยไงล่ะ (ทำไมมันดีจัง ทำไมมันดีกว่าชาวบ้านเขา!) ใครยังนึกภาพไม่ออกเดี๋ยวผมมีตัวอย่าง

วิธีจัดการแบบเดิม #

ตามปกติเวลาเราจะใช้ Vuex ถ้าเราอยากทำ app Todo list เราก็คงต้องเขียนอะไรประมาณนี้ใช่ไหมครับ

ที่ store/index.js ประกาศใน state และสร้าง actions และ mutations function ประมาณนี้

store: {
  state: { todos: [] },
  actions: {
      toggleStatus({ commit, state }, todoId) {
        const todo = state.todos.find(todo => {
          return todo.id === id
        });
        commit(SET_TODO_STATUS, { id: todoId, status: !todo.done});
      }
  },
  mutations: {
    SET_TODO_STATUS(state, payload) {
      const todo = state.todos.find(todo => {
          return todo.id === payload.id
      });
      todo.done = payload.status;
    }
  }
}

ที่ Components/TodoList.vue

<template>
  <todo-item 
    v-for="todo in todos"
    :key="todo.id"
    :todo="todo"
    @click="toggleStatus(todo.id)"
  />
</template>
<script>
  ...
  export default {
    ...
    computed: {
      todos() {
        return this.$store.state.todos;
      }
    },
    methods: {
      toggleStatus(id) {
        this.$store.dispatch('toggleStatus', id);
      }
    }
  }
</script>

ลองนึกภาพ TodoList ที่มันต้องมีทั้ง create, update, delete เพิ่มมาอีกสิครับยาวอยู่นะ

ถ้าพึ่งบารมี Vuex-ORM ล่ะจะเป็นอย่างไร #

ขั้นแรกเราก็สร้าง Model กันก่อนครับ กำหนดไปก่อนเลยว่ามี field อะไรบ้างแล้วจะให้มันอยู่ใน entity ไหน

store/models/Todo.js

import { Model } from '@vuex-orm/core';

export default class Todo extends Model {
    static entity = 'todos';

    static fields() {
      return {
        id: this.string(''),
        title: this.string(''),
        done: this.boolean(false),
      };
    }
}

store/index.js ก็มา register ตัว Model ที่เราสร้างไว้เมื่อสักครู่กับ database ของ Vuex-ORM

import Vue from 'vue';
import Vuex from 'vuex';
import VuexORM from '@vuex-orm/core';
import Todo from './models/Todo';

Vue.use(Vuex);

const database = new VuexORM.Database();
database.register(Todo);

const store = new Vuex.Store({
  plugins: [VuexORM.install(database)],
});

export default store;

ส่วนของ component code จะน่ารักขึ้นเยอะเลย

<template>
  <div>
    <todo-item
      v-for="todo in todos"
      :key="todo.id"
      :todo="todo"
      @clicked="toggleStatus"
    />
  </div>
</template>

<script>
import TodoItem from '../components/TodoItem.vue';
import Todo from '../store/models/Todo';
export default {
  ...
  computed: {
    todos() {
      return Todo.all();
    },
  },
  methods: {
    toggleStatus(id) {
      const todo = Todo.find(id);
      Todo.update({
        where: id,
        data: { done: !todo.done },
      });
    },
  },
};
</script>

สังเกตไหมครับว่า code มันดูเป็นผู้เป็นคนมากขึ้น เราสามารถเรียก Todo ได้แบบนี้เลย

//แบบเดิม
this.$store.dispatch('toggleStatus', id);

//แบบ vuex-orm
const todo = Todo.find(id);
Todo.update({
  where: id,
  data: { done: !todo.done },
});

มันเหมือนจะยาวขึ้นนะ แต่ผมว่ามันเข้าใจง่ายกว่ามาก แถมนอกจาก update แล้วยังมี create, insert, delete ให้ด้วยนะครับ หรือแม้แต่จะ query แบบนี้

//หา todo ที่ยังไม่ done มาทั้งหมด
const todos = Todo.query().where('done', false).get();

ก็ทำได้โดยที่เราไม่ต้องไปเขียน function query เลยครับ Vuex-ORM เขามี Query Builder มาให้ในตัวแล้วสะดวกมากๆ

มี plugin ด้วยนะ #

นอกเหนือไปจากความสบายที่บอกไปแล้ว ยังมี plugin อีกนะ (plugin ของ plugin) แน่นอนว่าปัจจุบัน app เราก็ต้องทำงานกับ API อยู่แล้ว ตัวที่น่าจะได้ใช้กันก็มี

  • Vuex ORM Axios - สำหรับใครที่ทำงานกับ RESTful API
  • Vuex ORM GraphQL - สำหรับใครที่ใช้ GraphQL ก็มีด้วย แล้วตัวนี้เจ๋งขนาดที่มันเขียน query ให้เราได้เองเลยแหละ

สำหรับใครที่อยากลองไปศึกษาเพิ่มเติมก็สามารถเข้าไปดูได้ที่ Github repo ของผู้พัฒนาได้เลยครับ มีให้อ่านครบทุกอย่าง งงตรงไหนไปเปิดหาใน issue ใน repo ก่อน ถ้าไม่เจอก็หาใน StackOverflow ต่ออีกที แต่ถ้ายังงงจริงๆ ก็ inbox มาถามผมได้ที่ Facebook Page นะครับ (ถ้าผมตอบได้นะ 5555)

https://github.com/vuex-orm/vuex-orm