Chào mừng đến với Cafedev! Trong bài viết hôm nay, chúng ta sẽ khám phá về chủ đề Pinia Vuejs với Getters. Getters không chỉ là một phần quan trọng của Pinia, mà còn là công cụ mạnh mẽ để truy xuất và xử lý dữ liệu trong Vue Pinia. Cafedev sẽ hướng dẫn bạn cách sử dụng getters một cách linh hoạt và hiệu quả trong quá trình phát triển ứng dụng Vuejs. Hãy cùng bắt đầu khám phá ngay bây giờ!


Getters chính xác là tương đương với giá trị tính toán cho trạng thái của một Store. Chúng có thể được định nghĩa với thuộc tính getters trong defineStore(). Chúng nhận state làm tham số đầu tiên để khuyến khích việc sử dụng arrow function:

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
})

Hầu hết thời gian, getters chỉ phụ thuộc vào trạng thái. Tuy nhiên, chúng có thể cần sử dụng các getters khác. Do đó, chúng ta có thể truy cập vào toàn bộ instance của store thông qua this khi định nghĩa một hàm thông thường nhưng cần phải định nghĩa kiểu trả về (trong TypeScript). Điều này là do một hạn chế đã biết trong TypeScript và không ảnh hưởng đến getters được định nghĩa bằng arrow function hoặc getters không sử dụng this:

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // automatically infers the return type as a number
    doubleCount(state) {
      return state.count * 2
    },
    // the return type **must** be explicitly set
    doublePlusOne(): number {
      // autocompletion and typings for the whole store ✨
      return this.doubleCount + 1
    },
  },
})

Sau đó, bạn có thể truy cập trực tiếp vào getter trên instance của store:

<script setup>
import { useCounterStore } from './counterStore'

const store = useCounterStore()
</script>

  <p>Double count is {{ store.doubleCount }}</p>

1. Truy cập các getters khác

Giống như các thuộc tính tính toán, bạn có thể kết hợp nhiều getters. Truy cập bất kỳ getter nào khác qua this. Trong tình huống này, bạn sẽ cần chỉ định một kiểu trả về cho getter.
code-group

[counterStore.ts]
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount(state) {
      return state.count * 2
    },
    doubleCountPlusOne(): number {
      return this.doubleCount + 1
    },
  },
})
[counterStore.js]
// You can use JSDoc (https://jsdoc.app/tags-returns.html) in JavaScript
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // type is automatically inferred because we are not using `this`
    doubleCount: (state) => state.count * 2,
    // here we need to add the type ourselves (using JSDoc in JS). We can also
    // use this to document the getter
    /**
     * Returns the count value times two plus one.
     *
     * @returns {number}
     */
    doubleCountPlusOne() {
      // autocompletion ✨
      return this.doubleCount + 1
    },
  },
})

2. Truyền đối số cho getters

Getters chỉ là computed properties bên trong, vì vậy không thể truyền bất kỳ tham số nào cho chúng. Tuy nhiên, bạn có thể trả về một hàm từ getter để chấp nhận bất kỳ đối số nào:

export const useStore = defineStore('main', {
  getters: {
    getUserById: (state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})

và sử dụng trong component:

<script setup>
import { storeToRefs } from 'pinia'
import { useUserListStore } from './store'

const userList = useUserListStore()
const { getUserById } = storeToRefs(userList)
// note you will have to use `getUserById.value` to access
// the function within the <script setup>
</script>

  <p>User 2: {{ getUserById(2) }}</p>

Lưu ý rằng khi làm điều này, getters không được lưu vào bộ nhớ cache nữa. Chúng chỉ là các hàm bạn gọi. Tuy nhiên, bạn có thể cache một số kết quả bên trong chính getter, điều này không phổ biến nhưng có thể hiệu quả hơn:

export const useStore = defineStore('main', {
  getters: {
    getActiveUserById(state) {
      const activeUsers = state.users.filter((user) => user.active)
      return (userId) => activeUsers.find((user) => user.id === userId)
    },
  },
})

3. Truy cập getters của các stores khác

Để sử dụng các getters của một store khác, bạn có thể trực tiếp sử dụng nó bên trong getter:

import { useOtherStore } from './other-store'

export const useStore = defineStore('main', {
  state: () => ({
    // ...
  }),
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

4. Sử dụng với setup()

Bạn có thể truy cập trực tiếp vào bất kỳ getter nào như một thuộc tính của store (chính xác như các thuộc tính trạng thái):

<script setup>
const store = useCounterStore()

store.count = 3
store.doubleCount // 6
</script>

5. Sử dụng với Options API


Đối với các ví dụ sau, bạn có thể giả định rằng store sau đã được tạo:

// Example File Path:
// ./src/stores/counter.js

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount(state) {
      return state.count * 2
    },
  },
})

5.1 Với setup()

Mặc dù Composition API không phải dành cho mọi người, hook setup() có thể làm cho việc sử dụng Pinia dễ dàng hơn trong Options API. Không cần thêm các hàm helper bản đồ thêm!

<script>
import { useCounterStore } from '../stores/counter'

export default defineComponent({
  setup() {
    const counterStore = useCounterStore()

    // **only return the whole store** instead of destructuring
    return { counterStore }
  },
  computed: {
    quadrupleCounter() {
      return this.counterStore.doubleCount * 2
    },
  },
})
</script>

Điều này hữu ích khi di chuyển một component từ Options API sang Composition API nhưng chỉ nên là một bước di chuyển. Luôn cố gắng không kết hợp cả hai phong cách API trong cùng một component.

5.2 Không có setup()

Bạn có thể sử dụng cùng một hàm mapState() được sử dụng trong bài trạng thái để ánh xạ đến getters:

import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counter'

export default {
  computed: {
    // gives access to this.doubleCount inside the component
    // same as reading from store.doubleCount
    ...mapState(useCounterStore, ['doubleCount']),
    // same as above but registers it as this.myOwnName
    ...mapState(useCounterStore, {
      myOwnName: 'doubleCount',
      // you can also write a function that gets access to the store
      double: (store) => store.doubleCount,
    }),
  },
}

Cảm ơn bạn đã đồng hành cùng Cafedev trong hành trình tìm hiểu về Pinia Vuejs với Getters. Chúng ta đã cùng nhau khám phá về sức mạnh của getters trong quá trình phát triển ứng dụng Vuejs, giúp chúng ta truy xuất và xử lý dữ liệu một cách linh hoạt và hiệu quả. Hy vọng rằng những kiến thức và kinh nghiệm mà chúng ta đã chia sẻ sẽ giúp bạn tăng cường kỹ năng lập trình của mình. Đừng quên tiếp tục theo dõi các bài viết mới nhất trên Cafedev để cập nhật thông tin công nghệ hàng ngày. Hẹn gặp lại trong những bài viết tiếp theo!

Tham khảo thêm: MIỄN PHÍ 100% | Series tự học Vuejs từ cơ bản tới nâng cao

Các nguồn kiến thức MIỄN PHÍ VÔ GIÁ từ cafedev tại đây

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của CafeDev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!