Bài viết được sự cho phép bởi tác giả Sơn Dương
Hiện nay, Vuex vẫn là thư viện phổ biến nhất, được sử dụng trong hầu hết các dự án. Tuy nhiên, khi Pinia ra đời và được team phát triển Vue khuyến khích sử dụng đã thay đổi cuộc chơi.
Pinia thừa hưởng toàn bộ ưu điểm của Vuex và bổ sung nhiều tính năng hấp dẫn, nhưng vẫn giữ được tính gọn nhẹ và dễ sử dụng. Pinia thực sự là một ứng cử viên sáng giá để thay thế vuex.
Chúng ta cùng nhau tìm hiểu cách sử dụng Pinia này nhé!
Pinia là gì?
Pinia là thư viện quản lý state trong Vue (State Management), phục vụ cho việc lưu trữ và chia sẻ state giữa các component với nhau.
Về cơ bản thì Pinia tương tự với Vuex. Vì Pinia ra đời sau Vuex, nên Pinia thừa hưởng những thế mạnh của Vuex. Tất nhiên, Pinia tương thích hoàn toàn với cả hai phiên bản Vue 2.x và Vue 3.
Cấu trúc và cú pháp của Pinia cũng rất quen thuộc, cũng có action, store, getter… Nhưng các cài đặt và cấu hình store cho Pinia lại đơn giản đến bất ngờ.
Với xu hướng được sử dụng ngày càng nhiều, Pinia có lẽ sẽ sớm thay thế Vuex trong tương lai gần thôi.
Tại sao chọn Pinia thay thế Vuex
Trong số các ưu điểm của thư viện Pinia, cá nhân mình thấy nó nổi trổi nhất ở các điểm sau:
- Kích thước thư viện siêu nhẹ, chỉ khoảng 1kb
- Hỗ trợ module hóa tốt
- Hỗ trợ auto complete khi code tốt. Thay vì phải khai báo mapAction(…), mapGetter(…).v.v…
- Dễ sử dụng, vì cách viết giống như bạn vẫn khai báo và sử dụng state trong từng component vậy.
Và còn nhiều ưu điểm khác nữa. Mình nghĩ sau khi thực hành và ứng dụng vào dự án, bạn sẽ trải nghiệm và nhận ra các ưu điểm này.
Xem thêm nhiều tuyển dụng VueJS hấp dẫn trên TopDev
Thực hành quản lý state sử dụng Pinia
Trước hết, chúng ta tạo mới một dự án Vue để thực hành đã nhé.
Vẫn câu lệnh quen thuộc:
vue create hello-pinia
(Dạo này đứt cáp quang biển nên việc tải thư viện, cài đặt dependencies lâu quá!)
Sau khi tạo xong dự án, bạn chạy thử dự án:
npm run serve
Vào trình duyệt để kiểm tra kết quả: http://localhost:8080
Trong bài viết này, mình sẽ sử dụng phiên bản Vue 3 cho nó hiện đại
Cài đặt và cấu hình Store với Pinia
Cài đặt Pinia cũng tương tự như các thư viện khác thôi. Chúng ta sẽ cài đặt qua npm bằng câu lệnh:
npm install pinia
Sau khi cài xong, quay trở lại main.js để thêm pinia vào Vue.
import { createApp } from 'vue' import App from './App.vue' import { createPinia } from "pinia"; createApp(App).use(createPinia()).mount('#app')
Bước tiếp theo là cấu hình store với Pinia.
Pinia có cách tiếp cận hơi khác một chút so với Vuex. Đó là Pinia xử lý state global theo hướng module. Tức là nó sẽ tạo nhiều store nhỏ lẻ tương ứng với một key duy nhất. Sau đó, Pinia sẽ kết hợp chúng lại thành một store duy nhất cho toàn ứng dụng.
Một store có 4 thuộc tính:
- ID: là khóa duy nhất như đã đề cập ở trên để xác định store
- state: là một hàm trả về trạng thái dữ liệu ban đầu của state
- getters: là nơi định nghĩa các giá trị cần lấy từ store
- actions: là nơi định nghĩa các hành động cập nhật state. Nó là sự kết hợp của action + mutation so với Vuex.
Ví dụ một đoạn code định nghĩa store bằng Pinia:
import { defineStore } from "pinia"; export const useTodoStore = defineStore({ id: "uniqueID", state: () => ({ // ... }), getters: { // ... }, actions: { // ... }, });
Thực hành dự án với Pinia
Quay trở lại với dự án mà chúng ta đã tạo trước đó. Với dự án này, chúng ta sẽ xây dựng một ứng dụng quản lý công việc siêu đơn giản.
Có 2 tính năng chính:
- Tạo mới công việc.
- Hiển thị danh sách công việc.
- Xóa một công việc
Giao diện ứng dụng khi hoàn thành sẽ như sau:
Đầu tiên, chúng ta sẽ cài đặt store với 2 actions cơ bản là: addTodo, removeTodo.
// stores/todo.ts import { defineStore } from "pinia"; export const useTodoStore = defineStore({ id: "todoState", state: () => ({ todos: [], }), getters: { totalTodos: (state) => state.todos.length, }, actions: { addTodo(title, description) { const todo = { id: Math.floor(Math.random() * 10000), // random ID title, description, }; this.todos = [todo, ...this.todos]; }, async removeTodo(id) { // remove todos this.todos = this.todos.filter((todo) => todo.id !== id); }, }, });
Về phần giao diện, mình chia nhỏ giao diện thành 2 components chính: Phần nhập công việc mới và phần danh sách các công việc.
Trong phần này, các bạn chú ý tới hàm setup()
. Đây là nơi mình khai báo tham chiếu tới store: const storeTodo = useTodoStore()
nhờ đó mà mình có thể gọi tới actions và truy xuất giá trị của global state.
<!-- components/TodoForm.vue --> <template> <form @submit="onSubmit"> <h2>VNTALKING - Quản lý công việc</h2> <!-- title --> <div class="field"> <label class="label">Tiêu đề</label> <input type="text" class="input" name="title" v-model="title" /> </div> <!-- description --> <div class="field"> <label class="label">Miêu tả</label> <textarea class="input" name="description" v-model="description"></textarea> </div> <!-- submit --> <div class="field"> <button type="submit">Tạo mới công việc</button> </div> </form> </template> <script> import { defineComponent } from "vue"; import { useTodoStore } from "../stores/todo"; export default defineComponent({ name: "TodoForm", data() { return { title: "", description: "", }; }, setup() { const storeTodo = useTodoStore(); return { storeTodo }; }, methods: { onSubmit(e) { e.preventDefault(); if (!this.title) { return; } // save data into store this.storeTodo.addTodo(this.title, this.description); // clear data this.title = ""; this.description = ""; }, }, }); </script>
Và danh sách công việc:
<!-- components/TodoList.vue --> <template> <div> <div v-for="todo of storeTodo.todos" :key="todo.id" class="wrapper"> <div class="header"> <div class="title">[{{ todo.id }}] {{ todo.title }}</div> <div> <button type="button" @click="storeTodo.removeTodo(todo.id)">Xóa</butto</div> </div> <div v-if="todo?.description">{{ todo?.description }}</div> </div> </div> </template> <script> import { defineComponent } from "vue"; import { useTodoStore } from "../stores/todo"; export default defineComponent({ name: "TodoList", setup() { const storeTodo = useTodoStore(); return { storeTodo }; }, }); </script>
Như bạn cũng thấy, với cách viết của Pinia, mình không cần phải sử dụng mapActions(...)
hay mapGetters(...)
mà VS Code vẫn tự động gợi ý lệnh. Đây là điều mà mình cảm thấy hứng thú nhất với Pinia so với Vuex!
Các bạn có thể tải mã nguồn đầy đủ về tham khảo:
Tạm kết
Sau khi trải nghiệm quản lý state với Pinia xong, cám giác của bạn thế nào? Có thấy Pinia xứng đáng để thay thế Vuex ở thời điểm hiện tại này không?
Có lẽ không phải ngẫu nhiên mà team phát triển Vue lại khuyến khích sử dụng Pinia. Chắc chắn họ cũng nhận ra những ưu điểm và cũng có chiến lược phát triển Vue tương đồng với Pinia.
Bài viết gốc được đăng tải tại vntalking.com
Xem thêm:
- Bộ guide để viết code sạch dành riêng cho Vue
- Lựa chọn Vue hay React dành cho FE Developer
- Giới thiệu framework Vue.js
Xem thêm các việc làm IT hấp dẫn trên TopDev