+4

Destructuring Props Object và Vấn đề về Reactivity trong Vue 3

Giới thiệu

Trong Vue 3, việc sử dụng destructuring (phân rã) để truy cập vào các thuộc tính của props object trong component con là một phương pháp tiện lợi.

Tuy nhiên, khi sử dụng destructuring như vậy, có một vấn đề liên quan đến reactivity (tính phản ứng) có thể xảy ra. (mình đã từng dính bug =))

Hôm nay, chúng ta sẽ tìm hiểu về vấn đề này thông qua một ví dụ cụ thể và đề xuất cách sửa khi sử dụng destructuring cho props object trong Vue 3.

Vấn đề về Reactivity khi Destructuring Props Object:

Khi sử dụng destructuring để truy cập vào các thuộc tính của props object trong component con, một vấn đề về reactivity có thể phát sinh.

Khi các thuộc tính props được destructuring, chúng sẽ trở thành các biến nguyên thuỷ (primitive variables) trong phạm vi của component con, và mất đi tính năng reactivity tự động của Vue.

Điều này có nghĩa là các thay đổi trong data của component cha sẽ không được phản ánh ngay lập tức vào component con.

Ví dụ về Vấn đề Reactivity khi Destructuring Props Object:

Giả sử chúng ta có một component cha (Parent) và một component con (Child).

Component cha chứa một thuộc tính data message, và component con nhận message thông qua props object và sử dụng destructuring để truy cập vào giá trị của message.

Chúng ta mong đợi rằng khi giá trị message trong component cha thay đổi, giá trị trong component con cũng sẽ được cập nhật.

<!-- Parent.vue -->
<template>
  <div>
    <Child :message="message" />
    <button @click="updateMessage">Update Message</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello, Vue 3!',
    };
  },
  methods: {
    updateMessage() {
      this.message = 'Updated Message';
    },
  },
};
</script>

<!-- Child.vue -->
<template>
  <div>
    <p>{{ propMessage }}</p>
  </div>
</template>

<script>
export default {
  props: {
    message: String,
  },
  mounted() {
    const { message } = this; // Destructuring props object
    console.log(message); // Hiển thị giá trị hiện tại của message trong component con
  },
  computed: {
    propMessage() {
      return this.message;
    },
  },
};
</script>

Trong ví dụ trên, khi giá trị message được cập nhật trong component cha thông qua nút "Update Message", chúng ta mong đợi rằng giá trị trong component con cũng sẽ được cập nhật để hiển thị giá trị mới.

Tuy nhiên, khi sử dụng destructuring props object trong component con, giá trị message trong component con sẽ không được cập nhật, và không có thông báo console mới được hiển thị.

Cách Sửa vấn đề Reactivity:

Để sửa vấn đề reactivity thì nó cũng đơn giản thôi, khi sử dụng destructuring cho props object trong Vue 3, chúng ta có thể thay đổi cách truy cập vào giá trị props trong component con.

Thay vì sử dụng destructuring, chúng ta nên truy cập trực tiếp vào props object và sử dụng giá trị từ đó.

<!-- Child.vue -->
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: {
    message: String,
  },
  mounted() {
   const message = this.message; // Không sử dụng destructuring
    console.log(message); // Hiển thị giá trị hiện tại của message trong component con
  },
  computed: {
    propMessage() {
      return this.message;
    },
  },
};
</script>

Bằng cách truy cập trực tiếp vào props object và sử dụng giá trị từ đó, chúng ta đảm bảo tính chất reactive của Vue 3 vẫn hoạt động đúng. Khi giá trị message trong component cha thay đổi, giá trị trong component con sẽ được cập nhật và thông báo console mới sẽ được hiển thị.

Còn nếu muốn destructuring props object mà vẫn giữ được tính reactive thì chúng ta có thể dùng hàm toRef. Ví dụ:

<!-- Child.vue -->
<template>
  <div>
    <p>{{ propMessage }}</p>
  </div>
</template>

<script>
import { toRef } from 'vue';

export default {
  props: {
    message: String,
  },
  setup(props) {
    const propMessage = toRef(props, 'message');
    
    return {
      propMessage
    };
  },
};
</script>

Trong ví dụ trên, chúng ta sử dụng toRef(props, 'message') để tạo một ref object propMessage từ property message của props object. Khi message thay đổi, giá trị của propMessage cũng sẽ được cập nhật tự động.

Hàm toRef tạo ra một ref object mới từ props object và property tương ứng. Ref object này giữ liên kết với giá trị của props object, và khi giá trị đó thay đổi, ref object cũng sẽ được cập nhật tự động. Điều này đảm bảo rằng giá trị destructured của props object trong component con vẫn có tính chất reactive và sẽ được cập nhật khi có sự thay đổi trong component cha.

Vì vậy, sử dụng toRef là một cách tiếp cận tốt để sử dụng destructuring cho props object trong Vue 3 mà vẫn giữ tính chất reactive của framework.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.