# Vuex Introduction ###### Speaker: Dr. Sang Nguyen --- ### Tại sao lại sử dụng Vuex - Không thể dùng các phương pháp khác như props, event bus để trao đổi dữ liệu giữa các component vì sẽ quá phức tạp với dự án trung bình, lớn. - Vuex cho ta khả năng lưu trữ và chia sẻ data trong mà không phải đánh đổi về performance, testability hoặc maintainability. --- ### UI = f(state) ![](https://flutter.dev/assets/development/data-and-backend/state-mgmt/state-management-explainer-5495afe6c3d6162f145107fe45794583bc4f2b55be377c76a92ab210be74c033.gif) Nguồn: https://flutter.dev/docs/development/data-and-backend/state-mgmt/intro --- ## Vuex là gì? #### Định nghĩa - Là Pattern và Library quản lý state trong VueJS. #### Tính chất - Store tập trung (centralized store). - Có những qui tắc để dữ liệu chỉ có thể được thay đổi theo kiểu cách tiên đoán được (predictable fashion). - one-way data flow --- #### Nói 1 cách dễ hiểu - Vuex là 1 cách để nhiều components dùng chung state. - Mỗi view có thể phụ thuộc vào 1 phần của state chung đó. - Nhiều action khác nhau (từ các view khác nhau) có thể thay đổi/cập nhật chung 1 vài thành phần của state. - Tham khảo: - Single source of truth - Redux: predictable state container --- ### 1-way data flow chung ![](https://i.imgur.com/x7Agehc.png) --- ### Vuex diagram ![](https://i.imgur.com/jS9GIwF.png) --- ### Nhắc lại Single File Component (SFC) ```javascript= <template> <p>{{ greeting }} World!</p> </template> <script> module.exports = { data() { return { greeting: 'Hello' } } } </script> <style scoped> p { font-size: 2em; } </style> ``` --- - Code HTML, CSS, script của một Component trong cùng một file. - Tại sao? --- ## Câu trả lời - Làm giảm số lượng file. - Đồng nhất, move/copy 1 component từ nơi này sang nơi khác (dự án này qua dự án khác) thì nó luôn "đủ bộ". - Ví dụ: Coupon của Phòng chăm sóc khách hàng và Phòng giáo dục. --- ## Các thành phần của Vuex **Các thành phần** - State - Mutation - Actions - Getters --- ## State - State là một object (singleton) chứa các properties được dùng chung trong nhiều nơi khác nhau của ứng dụng. - State gần giống 1 global object, ngoại trừ: - Vuex store có tính reactive: những **Component** sẽ reactive với **State**, tự động cập nhật nếu State thay đổi. - Ta không thể thay đổi state một cách trực tiếp. - Thay đổi state bắt buộc phải commit một mutation. --- - Cách khai báo ```javascript= import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 } }) ``` - Cách sử dụng ```javascript= // Cách 1 computed: { count() { return this.$store.state.count} } ``` --- ``` // Cách 2 import { mapState } from 'vuex' computed: mapState([ // map this.count to store.state.count 'count' ]) ``` --- ## Mutation Là cách duy nhất trong Vuex để thay đổi state ```javascript= const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } }) store.commit('increment') ``` --- #### Commit with Payload ```javascript= //Khai báo mutations: { increment (state, payload) { state.count += payload } } //Sử dụng store.commit('increment', 10) ``` --- #### Object-Style Commit > Không khuyến cáo - Tự tìm hiểu --- #### Nguyên tắc sử dụng Mutations dựa trên Vuex Reactive Rules --- #### Using Constants for Mutation Types - Một file cho thấy cái nhìn tổng quan về mutations. - Tránh khai báo trùng tên mutation. - Đây 1 là good practice - Nên follow. --- #### Mutations Must Be Synchronous - Luôn luôn là code synchronous (Không có callback/promise/async/await) --- ## Action - Nếu Mutation để commit state change thì Action để commit mutation - Được phép dùng asynchronous ``` Mutation: setCount this.state.count = a; Action store.commit('setCount', a); ``` --- ## Getter - Sử dụng khi cần thực hiện một operation gì đó từ dữ liệu của **State**. - Có thể hiểu như là những **computed properties** trong Store. - Tránh trùng lặp code. - Ví dụ: Thay vì phải viết lại một computed cho nhiều component ```javascript= computed: { doneTodosCount () { return this.$store.state.todos.filter(todo => todo.done).length } } ``` --- Thì có thể khai báo getter trong store để sử dụng được mọi nơi ```javascript= const store = new Vuex.Store({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } }) ``` --- Sử dụng getter ```javascript= store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }] ``` Sử dụng mapGetters trong phần computed của các components ```javascript= import { mapGetters } from 'vuex' computed: { ...mapGetters([ 'doubleCounter', 'stringCounter' ]), ourOwn() } ``` --- ## Phát biểu cảm nghĩ về Vuex - Ban đầu: Quá nhiều qui tắc làm ta gò bó. - Sau 2 tháng: Những qui tắc cho ta được tự do hơn.