Appearance
Provide / Inject
Truyền Thông Tin Bằng Props
Thường, khi chúng ta cần truyền dữ liệu từ cha đến một thành phần con, chúng ta sử dụng props. Tuy nhiên, hãy tưởng tượng trường hợp mà chúng ta có một cây thành phần lớn và một thành phần lồng sâu cần một thông tin từ một thành phần tổ tiên xa xôi. Chỉ với props, chúng ta sẽ phải truyền cùng một prop qua toàn bộ chuỗi cha:
Chú ý rằng mặc dù thành phần <Footer>
có thể không quan tâm đến những prop này chút nào, nhưng nó vẫn cần khai báo và truyền chúng đi chỉ để <DeepChild>
có thể truy cập. Nếu có một chuỗi cha dài hơn, nhiều thành phần khác nhau sẽ bị ảnh hưởng trên đường đi. Điều này được gọi là "truyền thông tin bằng props" và chắc chắn không phải là điều dễ chịu để xử lý.
Chúng ta có thể giải quyết vấn đề truyền thông tin bằng props bằng cách sử dụng provide
và inject
. Một thành phần cha có thể là một nhà cung cấp phụ thuộc cho tất cả con cháu của nó. Bất kỳ thành phần nào trong cây con, bất kể có sâu đến đâu, đều có thể chèn (inject) các phụ thuộc được cung cấp bởi các thành phần ở trên nó trong chuỗi cha.
Provide
Để cung cấp dữ liệu cho các con cháu của một thành phần, sử dụng hàm provide()
:
vue
<script setup>
import { provide } from 'vue'
provide(/* key */ 'message', /* value */ 'hello!')
</script>
Nếu không sử dụng <script setup>
, hãy đảm bảo provide()
được gọi đồng bộ bên trong setup()
:
js
import { provide } from 'vue'
export default {
setup() {
provide(/* key */ 'message', /* value */ 'hello!')
}
}
Hàm provide()
chấp nhận hai đối số. Đối số đầu tiên được gọi là khóa tiêm (injection key), có thể là một chuỗi hoặc một Symbol
. Khóa tiêm được sử dụng bởi các thành phần con để tìm giá trị mong muốn để chèn. Một thành phần duy nhất có thể gọi provide()
nhiều lần với các khóa tiêm chèn khác nhau để cung cấp các giá trị khác nhau.
Đối số thứ hai là giá trị được cung cấp. Giá trị có thể là bất kỳ kiểu nào, bao gồm cả trạng thái phản ứng như refs:
js
import { ref, provide } from 'vue'
const count = ref(0)
provide('key', count)
Việc cung cấp giá trị phản ứng cho phép các thành phần con sử dụng giá trị được cung cấp thiết lập một kết nối phản ứng với thành phần cung cấp.
Cung Cấp Ở Cấp Ứng Dụng
Ngoài việc cung cấp dữ liệu trong một thành phần, chúng ta cũng có thể cung cấp ở cấp ứng dụng:
js
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* key */ '
message', /* value */ 'hello!')
Cung cấp ở cấp ứng dụng sẽ có sẵn cho tất cả các thành phần được hiển thị trong ứng dụng. Điều này đặc biệt hữu ích khi viết plugins, vì các plugin thường không thể cung cấp giá trị bằng cách sử dụng thành phần.
Chèn Dữ Liệu
Để chèn dữ liệu được cung cấp bởi một thành phần tổ tiên, sử dụng hàm inject()
:
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
Nếu giá trị được cung cấp là một ref, nó sẽ được chèn như vậy và không tự động được mở gói. Điều này cho phép thành phần chèn giữ kết nối phản ứng với thành phần cung cấp.
Ví dụ đầy đủ về provide + inject với Reactivity
Một lần nữa, nếu không sử dụng <script setup>
, inject()
chỉ nên được gọi đồng bộ bên trong setup()
:
js
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}
[Ví dụ đầy đủ về provide + inject](https://play.vuejs.org/#eNqNkcFqwzAQRH9l0EUthOhuRKH00FO/oO7B2JtERZaEvA4F43+vZCdOTAIJCImRdpi32kG8h7A99iQKobs6msBvpTNt8JHxcTC2wS76FnKrJpVLZelKR39TSUO7qreMoXRA7ZPPkeOuwHByj5v8EqI/moZeXudCIBL30G0VNBS11VeyogD2StTwvldbZH0Bv0pBvKi3FIKlvFGcxEJ8r7nPWLlm3h5e6ik9yrrU/MFR8cdYrRno2xrk88/77KInS8xR8T8yt37jqD+aVebA7qHsFb+fPz3H8Xy
Đặt Tên Chèn
Khi sử dụng cú pháp mảng cho inject
, các thuộc tính được chèn được hiển thị trên thể hiện thành phần bằng cùng một khóa. Trong ví dụ trên, thuộc tính được cung cấp dưới khóa "message"
, và được chèn là this.message
. Khóa cục bộ là giống như khóa chèn.
Nếu chúng ta muốn chèn thuộc tính bằng cách sử dụng một khóa cục bộ khác, chúng ta cần sử dụng cú pháp đối tượng cho tùy chọn inject
:
js
export default {
inject: {
/* khóa cục bộ */ localMessage: {
from: /* khóa chèn */ 'message'
}
}
}
Ở đây, thành phần sẽ xác định một thuộc tính được cung cấp với khóa "message"
, và sau đó hiển thị nó như là this.localMessage
.
Giá Trị Mặc Định Cho Chèn
Mặc định, inject
giả định rằng khóa được chèn được cung cấp ở đâu đó trong chuỗi cha. Trong trường hợp khóa không được cung cấp, sẽ xuất hiện một cảnh báo thời gian chạy.
Nếu chúng ta muốn làm cho thuộc tính được chèn hoạt động với các nhà cung cấp tùy chọn, chúng ta cần khai báo một giá trị mặc định, tương tự như props:
js
// `value` sẽ là "default value"
// nếu không có dữ liệu nào khớp với "message" được cung cấp
const value = inject('message', 'default value')
Trong m
ột số trường hợp, giá trị mặc định có thể cần được tạo bằng cách gọi một hàm hoặc khởi tạo một lớp mới. Để tránh tính toán không cần thiết hoặc tác động phụ trong trường hợp giá trị tùy chọn không được sử dụng, chúng ta có thể sử dụng một hàm nhà máy để tạo giá trị mặc định:
js
const value = inject('key', () => new ExpensiveClass(), true)
Tham số thứ ba chỉ ra rằng giá trị mặc định nên được xem xét như là một hàm nhà máy.
Làm Việc với Phản Ứng
Khi sử dụng giá trị cung cấp / chèn phản ứng, đề xuất giữ bất kỳ sự thay đổi nào đối với trạng thái phản ứng bên trong người cung cấp nếu có thể. Điều này đảm bảo rằng trạng thái được cung cấp và những sự thay đổi có thể xảy ra đều nằm ở cùng một thành phần, làm cho việc duy trì nó dễ dàng hơn trong tương lai.
Có những lúc chúng ta cần cập nhật dữ liệu từ một thành phần chèn. Trong những trường hợp như vậy, chúng ta đề xuất cung cấp một hàm chịu trách nhiệm cho việc biến đổi trạng thái:
vue
<!-- bên trong thành phần cung cấp -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('Bắc Cực')
function updateLocation() {
location.value = 'Nam Cực'
}
provide('location', {
location,
updateLocation
})
</script>
vue
<!-- trong thành phần chèn -->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>
Cuối cùng, bạn có thể bọc giá trị được cung cấp bằng readonly()
nếu bạn muốn đảm bảo rằng dữ liệu được truyền qua provide
không thể bị biến đổi bởi thành phần chèn.
vue
<script setup>
import { ref, provide, readonly } from 'vue'
const count = ref(0)
provide('read-only-count', readonly(count))
</script>