# 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)

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

---
### Vuex diagram

---
### 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.