Vuex Cho Người Mới Bắt Đầu

2119

Vuex là gì?

Theo như định nghĩa của trang chủ thì nguyên văn nó như thế này :

Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion. It also integrates with Vue’s official devtools extension to provide advanced features such as zero-config time-travel debugging and state snapshot export / import

Định nghĩ thì có vẻ khó hiểu như vậy nhưng ta có thể hiểu một cách nôm na Vuex là một pattern + library của Vuejs, nó có chức năng như một cái kho chứa tập trung các state của các component trong ứng dụng. Khi chúng ta cần thay đổi gì chỉ cần tương tác trực tiếp với thằng state trên store của Vuex, mà không cần phải thông qua quan hệ giữa các component.

Để hiểu hơn là tại sao phải cần đến Vuex ta sẽ qua một ví dụ sau:

Chúng ta có 2 component là Counter chứa 2 chức năng là increment – decrement và component Result có chức năng in ra kết quả

  • Với trường hợp không sử dụng Vuex thì chúng ta sẽ cần truyền sự kiện increment hoặc decrement từ Counter lên cho App và sau đó App sẽ cập nhật và truyền kết quả xuống cho thằng Result

Đây là trường hợp mới chỉ có một cấp. Vậy nếu cây phân cấp components của ứng dụng là rất nhiều thì điều gì sẽ xảy ra. Trông nó sẽ như thế này :

Sẽ rất là rối và khó quản lý thì ý tưởng của thằng này cũng tương tự như Redux nếu anh em nào đã từng học qua Redux. Thì Vuex cũng vậy, nó sẽ tạo ra một strore chung cho các state để dễ dàng quản lý và thao tác khi có thay đổi:

Cài Đặt

CDN

Nếu bạn đang dùng Vuejs dạng CDN như Jquery :

https://unpkg.com/vuex

nhớ tải cả Vuejs nhá Vuejs

NPM

Yarn

Sau khi kiểm tra trong package.json đã cài đặt thành công Vuex ta tạo 1 folder store và tạo file store.js

Vậy là đã có 1 cái store tập trung của Vuex rồi.

Các thành phần và cách sử dụng của chúng

1. State

  • Giống như ở mỗi component chúng ta thường có 1 đối tượng data chứa các biến của componet thì state ở đây cũng có thể hiểu chính là data của cả ứng dụng. Sử dụng một state duy nhất như thế này sẽ giúp ta đồng bộ được dữ liệu giữa các componet một cách nhanh chóng và chính xác.

  • Lấy ra giá trị của một biến trong state, thì cũng giống như cách lấy ta giá trị của một attribute trong đối tượng vậy.

 

Nếu trong state của chúng ta có nhiều biến và ta chỉ muốn lấy ra một số các biến nhưng lại không muốn gọi từng thứ một như thế kia, thì đừng lo đã có cách đó là sử dụng một helper tên là mapState. Nó sẽ sử dụng toán thử Spread (...Array) cú pháp này chỉ áp dụng được trong các phiên bản javascript ES6 trở lên thôi nhe.

state

Vậy là giờ ta có các giá trị result và value đã có thể lấy ra sử dụng mà không cần phải lấy từng giá trị một nữa. Đừng quên import mapState không lại bảo sao không chạy.

Sử dụng mapState thì có thể lấy ra giá trị nhưng không thể update được đâu, Docs thì không thấy nói update bằng cách này, nhưng mình thấy từ map mình cứ nghĩ là nó binding 2 chiều nên mình đã thử update state bằng cách này và không thấy được nên chắc nó chỉ để get state thôi.

2. Getters

Đôi khi chúng ta có một hàm cần tính toán dựa trên biến trong state mà cái hàm này lại xuất hiện ở nhiều component. Bây giờ chả nhẽ ở mỗi component ta lại lôi cái biến đó ra và tạo hàm tính toán lại ví dụ hàm lọc các công việc phải làm và đếm chúng:

Thì Vuex nó cho phép ta định nghĩa các hàm như thế này trong getters

 

Và lấy cũng đơn giản thôi:

 

Ta có thể sử dụng các hàm trong cùnggetters với nhau:

Còn ở trong các component khác thì cũng đơn giản không kém

 

Đã có mapSate thì cũng có mapGetters và cách dùng cũng tương tự:

 

Hoặc là lúc định nghĩ thì một tên nhưng lúc sử dụng ta muốn dùng tên khác cũng chẳng sao đổi được ý mà:

3. Mutations

  • Theo như Docs thì mutations là cách duy nhất mà ta có thể thay đổi thực sự state trong store. Và cách để kích hoạt một mutations đó là ta sẽ commit một chuỗi String chính là tên của hàm mà ta muốn gọi trong mutations, nó sẽ nhận state của store làm tham số đầu tiên:

Thấy nhà phát triển nói là cách duy nhất để thay đổi thực sự nhưng mình đã thử một cách và vẫn thấy nó thay đổi được đó là:

Mình vẫn thấy nó hoạt động nhưng không thấy Docs nói đến kiểu này hay là nó không chuẩn chỉ và có thể gây lỗi hay như thế nào. Nhưng hoi Docs đã viết cách này dùng để thay đổi, nên mình sẽ dùng cách này cho chắc không lại đến lúc có lỗi thì vỡ mồm.

  • Ngoài commit mỗi tên của hàm thì bạn cũng có thể truyền thêm một tham số bổ sung, nếu như hàm của bạn có định nghĩa nhiều hơn 1 tham số đầu vào là state

thường thì người ta sẽ gom các đối số thành một Object để có thể chứa được nhiều biến cần truyền vào hơn

Còn một cách nữa đó là gom cả tên hàm cần gọi và biến cần truyền vào 1 Object với tên hàm để là type vậy là mutations sẽ hiểu và thực hiện mà không cần thay đổi số tham số của hàm

Muntations thì cũng tuân theo Reactivity Rules của Vue. Nên nếu sau khi state đã được khởi tạo ta muốn thêm một biến mới vào trong state, thì ta cần khai báo cho Vue biết rằng ta có một mới muốn thêm vào hoặc là thay thế toàn bộ

  • Ta có thể dùng các mutations với dạng các hằng số. Điều này sẽ rất giúp ích cho việc đồng bộ tên hàm cũng như phù hợp cho các dự án lớn với nhiều bên tham gia

nhưng nó chỉ là một tùy chọn thôi nha bạn không nhất thiết cứ phải sử dụng nó đâu

=> Một điều cần nhớ đó là thằng mutations này sẽ chạy đồng bộ nên bạn cần cẩn thận khi sử dụng nó, không lại dối tung lên khi kết hợp nó với các hàm bất đồng bộ và không hiểu sao nó lại không chạy.

  • Giống như 2 thằng trên thì mutations cũng có helper đó là mapMutations

4. Actions

  • Actions cũng giống như mutations nhưng nó khác ở hai điểm:
    • Actions không trực tiếp thay đổi state trong store mà nó sẽ thông qua mutations để thay đổi
    • Nó có thể chứa các hàm bất đồng bộ

    Ví dụ đơn giản

 

Có thể sử dụng hàm argument destructuring để tạo

  • Cách kích hoạt 1 actions khi ở component khác

chúng ta cũng có thể truyền thêm một tham số

Và lại thêm một cái helper nữa đó là mapActions

5. Modules

  • Bây giờ mới có vài hàm thì nhét hết vào file store.js được chứ về sau mỗi biến trong state lại có hàng tá hàm thì rất rối. Thì Vuex đã hỗ trợ một tùy chỉnh đó là modules, ta có thể tách các hàm có chung mục đích ra một file như sau:

  • Nếu bạn muốn nhóm các kiểu mutation/action có chung mục đích sử dụng lại với nhau ta có thể sử dụng đinh nghĩa Namespacing với thuộc tính namespaced: true

  • Và khi binding với các helpers mà có sử dụng namespace trông nó sẽ như thế này:

Hoặc là đưa phần string namespace vào làm đối số đầu tiên

Còn nếu không muốn dùng lại những string namespace đó nhiều lần bạn có thể sử dụng createNamespacedHelpers. Nó sẽ trả về một đối tượng liên kết với các helper mà bạn muốn.

Ngoài ra bạn có thể đăng ký các module sau khi store đã được tạo với method store.registerModule

Cấu trúc ứng dụng

Theo hướng dẫn thì cấu trúc của ứng dụng Vuex nên như này

Để quản lý chặt chẽ hơn thì chúng ta nên kết hợp vừa tách thành các modules cho những đối tượng chứa nhiều hàm trong mutations, actions, getters và vừa tách ra các file actions, mutations dùng cho các đối tượng ít hàm hơn.

TechTalk via Viblo

CHIA SẺ