Truyền Dữ Liệu Giữa Các Component Trong Vue.js

Phát triển ứng dụng Vue theo mô hình component giúp chia nhỏ chức năng phức tạp thành các khối độc lập, giảm sự phụ thuộc và tăng khả năng bảo trì. Các component được phân loại thành:

  • Component trình diễn: Chỉ hiển thị dữ liệu nhận vào, không xử lý logic (càng ở tầng dưới càng đơn giản)
  • Component điều khiển: Xử lý nghiệp vụ chính, quản lý luồng dữ liệu (thường ở tầng trên)

Lợi ích chính khi áp dụng component hóa:

  1. Tăng tốc độ phát triển
  2. Khả năng tái sử dụng cao
  3. Phối hợp nhóm hiệu quả
  4. Quản lý và mở rộng dễ dàng

Quy tắc khai báo component

Vue.component('product-list', {
  template: `<div>Nội dung component</div>`
})

Cách đặt tên:

  • Dạng kebab-case: product-list (ưu tiên trong template HTML)
  • Dạng PascalCase: ProductList

Lưu ý quan trọng:

  • Khởi tạo trước khi tạo instance Vue chính
  • Tên component phải khớp khi sử dụng
  • Template chỉ có một root element
  • Trong component, data phải là hàm trả về object

Truyền dữ liệu từ cha xuống con

Sử dụng thuộc tính tùy chỉnh với v-bind:

<product-list :items="productData"></product-list>

Component con nhận dữ liệu qua props:

props: {
  items: {
    type: Array,
    required: true,
    default: () => []
  }
}

Ví dụ minh họa:

<div id="app">
  <product-list :items="products"></product-list>
</div>

const ProductCatalog = {
  props: {
    items: {
      type: Array,
      default: () => []
    }
  },
  template: `
    <ul>
      <li v-for="product in items" :key="product.id">
        {{ product.name }} - ${{ product.price }}
      </li>
    </ul>
  `
}

Vue.component('product-list', ProductCatalog)
new Vue({
  el: '#app',
  data: {
    products: [
      { id: 1, name: 'Laptop', price: 999 },
      { id: 2, name: 'Phone', price: 699 }
    ]
  }
})

Truyền dữ liệu từ con lên cha

Component cha lắng nghe sự kiện tùy chỉnh:

<product-list 
  :items="products" 
  @stock-update="handleStockChange"
></product-list>

Component con kích hoạt sự kiện qua $emit:

methods: {
  updateStock(id, inStock) {
    this.$emit('stock-update', id, inStock)
  }
}

Nguyên tắc quan trọng: Dữ liệu chỉ truyền một chiều từ cha xuống con. Component con không được trực tiếp sửa dữ liệu từ cha, mà phải thông báo qua sự kiện để cha cập nhật.

Ví dụ hoàn chỉnh với checkbox

<div id="app">
  <input v-model="newProduct" @keyup.enter="addProduct">
  <product-inventory 
    :products="inventory" 
    @toggle-stock="updateStockStatus"
  ></product-inventory>
</div>

const InventoryManager = {
  props: {
    products: {
      type: Array,
      default: () => []
    }
  },
  template: `
    <div>
      <ul>
        <li v-for="item in products" :key="item.id">
          <input 
            type="checkbox" 
            :checked="item.inStock"
            @change="toggleStock(item.id, $event)"
          >
          {{ item.name }}
        </li>
      </ul>
    </div>
  `,
  methods: {
    toggleStock(id, event) {
      this.$emit('toggle-stock', id, event.target.checked)
    }
  }
}

Vue.component('product-inventory', InventoryManager)
new Vue({
  el: '#app',
  data: {
    newProduct: '',
    inventory: [
      { id: 101, name: 'Keyboard', inStock: true },
      { id: 102, name: 'Mouse', inStock: false }
    ]
  },
  methods: {
    addProduct() {
      this.inventory.push({
        id: Date.now(),
        name: this.newProduct,
        inStock: true
      })
      this.newProduct = ''
    },
    updateStockStatus(id, status) {
      const product = this.inventory.find(p => p.id === id)
      if (product) product.inStock = status
    }
  }
})

Xử lý dữ liệu tham chiếu

Khi cần chỉnh sửa dữ liệu phức tạp, component con nên tạo bản sao riêng:

data() {
  return {
    localProducts: JSON.parse(JSON.stringify(this.products))
  }
}

Cách này tránh ảnh hưởng trực tiếp đến dữ liệu gốc từ component cha, đặc biệt quan trọng với object và array.

Thẻ: Vue.js props custom-events reactivity

Đăng vào ngày 10 tháng 7 lúc 03:01