VueJS

Vuex getting started!

Vuex getting started!

Hà Nội, những ngày chớm đầu hè mà đã thấy nong nóng @@. Cũng theo như dự báo thì năm 2020 này mùa hè sẽ nóng hơn cả hè năm 2019 @@.

1. Mở đầu

Theo như trang chủ VueX giới thiệu, thì nó là state management pattern + library.

VueX được sinh ra để quản lí các data là Singleton, hoặc để truyền sự kiện hay cũng có thể hiểu là để quản lí state và share data cho nhau giữa các Component.

2. Chi tiết

Trong phần này mình sẽ giới thiệu tổng quát các thành phần xung quanh sơ đồ này nhé.

Như các bạn có thể thấy ở đây chúng ta có một số Core concepts cần ghi nhớ đó là: State, Store, Getters, Actions, Mutations. Ở phần dưới chúng ta sẽ đi qua từng cái một và mình sẽ giới thiệu tổng quát đến cho các bạn nhé.

Trước khi vào chi tiết từng phần thì các bạn cần hiểu là khi dùng VueX thì các phần data là singleton sẽ được ưu tiên lưu vào store. Và khi đã lưu vào đây rồi, nếu muốn thay đổi các state này các bạn không được change trực tiếp mà bắt buộc phải change nó qua một action đến một mutations nào đó, ở đây mutations mới có thể change state của chúng ta nhé.

State

Ở đây các bạn cần hiểu state là nơi lưu giữ data trong từng component, với VueJS thì nó là các phần trong data nhé các bạn.

Và khi mà chúng ta add VueX vào Vue thì các bạn hiểu đơn giản là nó không cục bộ ở từng Component nữa mà nó sẽ được share cho các component, service khác trong hệ thống.

Vậy có bạn lại hỏi: Ơ thế cái gì cũng cho vào State của Redux à, liệu có nhiều quá không? Câu trả lời là không phải tất cả đều cho vào đó nhé các bạn. @@ cho vào nhiều vậy có mà chết à ^^. Chú ý là chỉ lên gắn những phần là singleton thôi nhé. Ở đây ta sẽ cần hiểu singleton nghĩa là ít thay đổi, hoặc không thay đổi trong suốt vòng đời của app nhé.

Store

Store là phần quản lí State, nó sẽ có các phương thức cho phép bạn có thể thay đổi state một cách gián tiếp thông qua dispatch hoặc một commit. Store là duy nhất bên trong một app, nó sẽ được khởi tạo cùng với root.

Getters

Ở đây các bạn có thể hiểu nó kiểu là một computed dùng để tính toán data, xử lí một cái logic chung nào đó mà nhiều component dùng. Hàm viết ở đây chỉ có thể dùng để lấy data ra chứ không thể modify (Liên hệ một chút là nó giống như Getter trong OOP vậy – thể hiện tính bao đóng).

Actions

Trong Action sẽ thường chứa logic liên quan đến business và các bạn nên hiểu là nó không trực tiếp thay đổi state. Nếu muốn thay đổi State thì các bạn cần dùng một Commit đã được định nghĩa tại Mutations. Lí do là bởi vì Actions thường được chạy bất đồng bộ (Code của bạn nó vẫn chạy khi mà actions chưa hoàn thành) và như vậy khi nó finished thì chúng ta mới lên Commit để change data.

Mutations

Các hàm trong Mutations thường sẽ không nên chứa logic hay business gì, nó chỉ nên có một việc là update state. Các bạn nên hiểu là nó chạy đồng bộ và nên biết là một hàm bên trong một Mutations được gọi là một Commit.

Ok, nói vậy tạm đủ rồi – các phần trên đó là các phần Core rồi nhé. Bây giờ chúng ta sẽ làm một cái ví dụ nhỏ nhỏ để hiểu thêm nhé các bạn.

Đầu tiên thì các bạn sẽ cần tạo một Vue app và cái VueX, bằng cách chạy lệnh sau: (Nếu các bạn chưa biết sao lại có lệnh vue thì các bạn hãy search Vue cli)
+ vue create demo-vuex
+ yarn add vuex or npm install vuex

Khi các bạn đã xong rồi thì chúng ta sẽ cùng làm nhé. Đầu tiên chúng ta sẽ tạo ra một folder store và viết một file index.js nhé.

import Vuex from 'vuex';
import Vue from 'vue';

Vue.use(Vuex);

export default new Vuex.Store({
    state: {
        username: 'Chamdev.com',
        age: 10
    },

    getters: {
        // Here we will create getter
    },

    mutations: {
        // Here we will create commit
    },

    actions: {
        // Here we will create action
    }
});

Để sử dụng được file này chúng ta sẽ cần import và inject nó vào bên trong đối tượng Vue root nhé các bạn. Các bạn chỉnh file main.js thành như sau:

import Vue from 'vue';
import App from './App.vue';
import store from './store';

Vue.config.productionTip = false;

new Vue({
    store,
    render: h => h(App),
}).$mount('#app');

Tiếp theo chúng ta sẽ cho hiện state trong store ra để xem thử nhé các bạn ^^, hãy cùng tạo ra một component và import nó vào bên trong App component root nhé.

<template>
    <div>
        <h1>Info</h1>
        <h2>{{username}}</h2>
        <h2>{{age}}</h2>
    </div>
</template>

<script>
import { mapState } from 'vuex';

export default {
    name: "Info",
    computed: {
        ...mapState(['username', 'age']),
    }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Ở đây mình đang dùng mapState vì mình đang dùng nhiều hơn 1 state trong store, nếu các bạn dùng một cái thôi thì lên chuyển thành như thế này nhé.

<template>
    <div>
        <h1>Info</h1>
        <h2>{{username}}</h2>
        <h2>{{age}}</h2>
    </div>
</template>

<script>
export default {
    name: "Info",
    computed: {
        username() {
            return this.$store.state.username;
        },
        age() {
            return this.$store.state.age;
        }
    }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Hãy so sánh 2 cách trên và cảm nhận (feeling ^^), cách nào đơn giản hơn, câu trả lời là tùy nhé: nếu không muốn viết thêm logic thì dùng cách đầu, còn nếu muốn viết thêm logic để hiện thì các bạn vẫn phải viết tường minh nó ra rồi chèn logic vào nhé.

Tiếp theo, chúng ta sẽ cùng update tiếp store/index.js nhé để xem tiếp actions và mutations nó hoạt động như thế nào ^^.

Chúng ta hãy cùng change file store/index.js nhé, ở đây các bạn hãy chú ý phần actions và mutations nhé.

import Vuex from 'vuex';
import Vue from 'vue';

Vue.use(Vuex);

export default new Vuex.Store({
    state: {
        username: 'Chamdev.com',
        age: 10
    },

    getters: {
        // Here we will create getter
    },

    mutations: {
        changeUsername(state, newUsername) {
            state.username = newUsername;
        }
    },

    actions: {
        handleChangeUsername(context, newUsername) {
            context.commit('changeUsername', newUsername);
        }
    }
});

Tiếp theo chúng ta sẽ change tiếp phần component của chúng ta nào.

<template>
    <div>
        <h1>Info</h1>
        <h2>{{username}}</h2>
        <br />
        <div>
            <input v-model="usernameInput"/>
            <button @click="changeUsername">Change username</button>
        </div>
    </div>
</template>

<script>
export default {
    name: "Info",
    data() {
        return {
            usernameInput: ''
        }
    },
    computed: {
        username() {
            return this.$store.state.username;
        }
    },
    methods: {
        changeUsername() {
            this.$store.dispatch('handleChangeUsername', this.usernameInput);
        }
    }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Ở đây nếu như các bạn làm thành công thì khi mà change usernameInput thì và click button [Change username] thì phần username của chúng ta sẽ được update nhé. Còn nếu gặp lỗi gì thì hãy đừng ngần ngại mà comment hỏi nhé.

Tiếp theo chúng ta sẽ xem tiếp getter nó chạy như thế nào nhé. Như phần trên mình đã giới thiệu thì đây là phần mà các logic xử lí, để có thể lấy ra state mà đã được tính toán. Các bạn lên viết getter nếu như nhiều component dùng lại hàm này nhé, còn không thì lấy state ra rồi tính lại ở từng component thôi.

Chúng ta sửa lại store/index.js thành như sau nhé:

import Vuex from 'vuex';
import Vue from 'vue';

Vue.use(Vuex);

export default new Vuex.Store({
    state: {
        username: 'Chamdev.com',
        age: 10
    },

    getters: {
        getUsername: state => {
            return "Username: " + state.username;
        },
        getAge: state => {
            return state.age + " year old.";
        }
    },

    mutations: {
        changeUsername(state, newUsername) {
            state.username = newUsername;
        }
    },

    actions: {
        handleChangeUsername(context, newUsername) {
            context.commit('changeUsername', newUsername);
        }
    }
});

Tiếp đó để hiển thị ra bên ngoài chúng ta sẽ chỉnh file component thành như sau nhé.

<template>
    <div>
        <h1>Info</h1>
        <h2>{{username}}</h2>
        <br />
        <div>
            <input v-model="usernameInput"/>
            <button @click="changeUsername">Change username</button>
        </div>
        <br />
        <div>
            <div>{{getUsername}}</div>
            <div>{{getAge}}</div>
        </div>
    </div>
</template>

<script>
// import { mapGetters } from 'vuex';

export default {
    name: "Info",
    data() {
        return {
            usernameInput: ''
        }
    },
    computed: {
        username() {
            return this.$store.state.username;
        },
        ...mapGetters(['getUsername', 'getAge']),
        // getUsername() {
        //     return this.$store.getters.getUsername;
        // },
        // getAge() {
        //     return this.$store.getters.getAge;
        // }
    },
    methods: {
        changeUsername() {
            this.$store.dispatch('handleChangeUsername', this.usernameInput);
        }
    }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Ở đây các bạn cũng có thể dùng thêm tính năng của VueX để làm cho code được ngắn gọn hơn nhé như là: mapGetters, mapActions , mapState, mapMutations. Thật là quá tiện ^^

3. Kết luận

Như vậy, các bạn chắc cũng hiểu một phần cơ bản nhất của VueX rồi chứ ạ. Nhưng bể học là vô biên, đây mới chỉ là một phần rất nhỏ mà bạn có thể làm với VueX thôi nhé. Nhưng mình tự tin nó là phần core quan trọng nhất. Nếu các bạn lắm được cơ bản như thế này rồi thì có sẽ làm quen với dự án dùng VueX rất nhanh thôi nhé.

Bài viết này được cập nhật vào ngày 06/05/2020.

4. Tham khảo

# Vuex made simple — getting started!
# What is Vuex?
# Vuex Tutorial

Tagged , , ,
0 0 vote
Article Rating
Subscribe
Notify of
guest
4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
NoName
NoName
6 months ago

Hay lắm bạn!

noob_vue
noob_vue
5 months ago

Rất tuyệt vời, bài việt thực sữ dễ hiểu. Mình đã đọc qua cái bài viết hướng dẫn về vuex thấy bài này ad viết hay nhất. Chúc ad sức khỏe viết thêm nhiều bài viết về Vuejs