Reaktivite Dönüştürme
Reaktivite Dönüştürme
Reaktivite Dönüştürme, deneysel bir özellikti ve en son 3.4 sürümünde kaldırıldı. Lütfen nedenini buradan okuyun.
Hala kullanmayı düşünüyorsanız, artık Vue Makroları eklentisi aracılığıyla mevcuttur.
Reaktivite Dönüştürme, Composition-API'ye özgü bir özelliktir ve bir derleme adımı gerektirir.
Refs vs. Reaktif Değişkenler
Composition API'nin tanıtılmasından bu yana, çözülemeyen temel sorulardan biri, refs ve reaktif nesnelerin kullanımıdır. Reaktif nesneleri çözümlerken reaktiviteyi kaybetmek kolaydır, oysa refs kullanıldığında her yerde .value
kullanmak zahmetli olabilir. Ayrıca, bir tür sistemi kullanılmadığı takdirde .value
kullanımı kolayca gözden kaçabilir.
Vue Reaktivite Dönüştürme, şu şekilde kod yazmamıza olanak tanıyan bir derleme zamanı dönüştürmesidir:
<script setup>
let count = $ref(0)
console.log(count)
function increment() {
count++
}
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
Buradaki $ref()
metodu, bir derleme zamanı makrosudır: bu, çalışma zamanı sırasında çağrılacak gerçek bir yöntem değildir. Bunun yerine, Vue derleyici bunu, elde edilen count
değişkenini bir reaktif değişken olarak ele alması için bir ipucu olarak kullanır.
Reaktif değişkenlere normal değişkenler gibi erişilebilir ve tekrar atama yapılabilir, ancak bu işlemler .value
ile refs'e derlenir. Örneğin, yukarıdaki bileşenin `` kısmı şu şekilde derlenir:
import { ref } from 'vue'
let count = ref(0)
console.log(count.value)
function increment() {
count.value++
}
Refs döndüren her reaktivite API'sinin bir $
ile başlayan makrosu olacaktır. Bu API'ler şunlardır:
ref
->$ref
computed
->$computed
shallowRef
->$shallowRef
customRef
->$customRef
toRef
->$toRef
Bu makrolar küresel olarak mevcuttur ve Reaktivite Dönüştürme etkinleştirildiğinde içe aktarım gerektirmez, ancak daha açık olmak isterseniz vue/macros
'tan içe aktarabilirsiniz:
import { $ref } from 'vue/macros'
let count = $ref(0)
$()
ile Çözümleme
Bir bileşim işlevinin refs nesnesini döndürmesi ve bu refs'i çözümlemek için çözümleme kullanması yaygındır. Bu amaçla, reaktivite dönüştürme $()
makrosunu sağlar:
import { useMouse } from '@vueuse/core'
const { x, y } = $(useMouse())
console.log(x, y)
Derlenmiş çıktı:
import { toRef } from 'vue'
import { useMouse } from '@vueuse/core'
const __temp = useMouse(),
x = toRef(__temp, 'x'),
y = toRef(__temp, 'y')
console.log(x.value, y.value)
Eğer x
zaten bir ref ise, toRef(__temp, 'x')
onu olduğu gibi döndürecektir ve ek bir ref oluşturulmayacaktır. Eğer bir çözümleme değeri bir ref değilse (örneğin bir fonksiyon), yine de çalışacaktır - değer bir ref içinde sarılacak ve diğer kodun beklendiği gibi çalışmasını sağlayacaktır.
$()
çözümleme, hem reaktif nesnelerde hem refs içeren düz nesnelerde çalışır.
Mevcut Refs'i Reaktif Değişkenlere Dönüştürme $()
ile
Bazı durumlarda, refs döndüren sarmalanmış fonksiyonlara sahip olabiliriz. Ancak, Vue derleyici, bir fonksiyonun bir ref döndüreceğini önceden bilemeyecektir. Bu tür durumlarda, $()
makrosu mevcut refs'i reaktif değişkenlere dönüştürmek için de kullanılabilir:
function myCreateRef() {
return ref(0)
}
let count = $(myCreateRef())
Reaktif Props Çözümleme
`içindeki mevcut
defineProps()` kullanımında iki acı noktası bulunmaktadır:
.value
gibi, reaktiviteyi korumak içinprops.x
olarak her zaman props'e erişmeniz gerekir. Bu,defineProps
'ı çözümlemekten alıkoyar çünkü sonuçta çözümlenen değişkenler reaktif değildir ve güncellenmeyecektir.Yalnızca türde props tanımı
kullanıldığında, props için varsayılan değerleri belirtmenin kolay bir yolu yoktur. Bu kesin amaç içinwithDefaults()
API'sini tanıttık, ancak kullanımı hala karmaşık.
Bu sorunları, $()
ile gördüğümüz gibi, çözümleme ile defineProps
kullanılırken bir derleme zamanı dönüştürmesi uygulanarak çözebiliriz:
<script setup lang="ts">
interface Props {
msg: string
count?: number
foo?: string
}
const {
msg,
// varsayılan değer sadece çalışır
count = 1,
// yerel takma adlandırma da sadece çalışır
// burada `props.foo`'yu `bar` olarak takma adlandırıyoruz
foo: bar
} = defineProps<Props>()
watchEffect(() => {
// props değiştiğinde günlüğe kaydedecek
console.log(msg, count, bar)
})
</script>
Yukarıdaki, şu şekilde derlenmiş bir çalışma zamanı bildirimine dönüştürülecektir:
export default {
props: {
msg: { type: String, required: true },
count: { type: Number, default: 1 },
foo: String
},
setup(props) {
watchEffect(() => {
console.log(props.msg, props.count, props.foo)
})
}
}
Fonksiyon Sınırları Boyunca Reaktiviteyi Koruma
Reaktif değişkenler, .value
kullanma zorunluluğundan kurtarırken, reaktif değişkenleri işlev sınırları arasında geçirirken "reaktivite kaybı" sorununu oluşturur. Bu iki durumda meydana gelebilir:
Bir argüman olarak işlevine geçiş
Bir ref olarak bir argüman bekleyen bir işlev verildiğinde, örneğin:
function trackChange(x: Ref<number>) {
watch(x, (x) => {
console.log('x değişti!')
})
}
let count = $ref(0)
trackChange(count) // çalışmıyor!
Yukarıdaki durum, beklenildiği gibi çalışmayacaktır çünkü şu şekilde derlenir:
let count = ref(0)
trackChange(count.value)
Burada count.value
bir sayı olarak geçerken, trackChange
gerçek bir ref beklemektedir. Bunu düzeltmek için count
'ı geçmeden önce $$()
ile sarmalayabiliriz:
let count = $ref(0)
- trackChange(count)
+ trackChange($$(count))
Yukarıdaki şu şekilde derlenir:
import { ref } from 'vue'
let count = ref(0)
trackChange(count)
Gördüğümüz gibi, $$()
reaktif değişkenler için kaçış ipucu olarak hizmet eden bir makrodur: $$()
içindeki reaktif değişkenlere .value
eklenmeyecektir.
Fonksiyon kapsamı içinde döndürme
Reaktif değişkenler, doğrudan döndürülen bir ifadede kullanılırsa reaktiviteyi kaybedebilir:
function useMouse() {
let x = $ref(0)
let y = $ref(0)
// mouse hareketini dinle...
// çalışmıyor!
return {
x,
y
}
}
Yukarıdaki return ifadesi şu şekilde derlenir:
return {
x: x.value,
y: y.value
}
Reaktiviteyi korumak için, aslında refs döndürmeliyiz, döndürme zamanında mevcut değeri değil.
Bu durumu düzeltmek için $$()
kullanabiliriz. Bu durumda, $$()
döndürülen nesne üzerinde doğrudan kullanılabilir - $$()
çağrısı içindeki reaktif değişkenlere dair herhangi bir referans, altında yatan refs'e olan referansı koruyacaktır:
function useMouse() {
let x = $ref(0)
let y = $ref(0)
// mouse hareketini dinle...
// düzeltildi
return $$({
x,
y
})
}
Çözümleme edilen props üzerinde $$()
kullanma
$$()
çözümlenen props'lar üzerinde çalışır çünkü bunlar da reaktif değişkenlerdir. Derleyici, bu durumu verimlilik için toRef
ile dönüştürecektir:
const { count } = defineProps<{ count: number }>()
passAsRef($$(count))
şu şekilde derlenir:
setup(props) {
const __props_count = toRef(props, 'count')
passAsRef(__props_count)
}
TypeScript Entegrasyonu
Vue, bu makrolar için (küresel olarak mevcut) tipler sunar ve tüm türler beklendiği gibi çalışacaktır. Standart TypeScript semantiklerinde herhangi bir uyumsuzluk yoktur, bu nedenle sözdizimi tüm mevcut araçlarla çalışacaktır.
Bu, makroların yalnızca geçerli JS/TS'nin izin verildiği dosyalarda - yalnızca Vue SFC'lerinde değil - çalışabileceği anlamına gelir.
Makrolar küresel olarak mevcut olduğundan, türlerinin açık bir şekilde referans verilmesi gerekir (örneğin bir env.d.ts
dosyasında):
/// <reference types="vue/macros-global" />
Makroları vue/macros
'tan açık bir şekilde içe aktarırken, türleri küresel olarak bildirimde bulunmadan çalışacaktır.
Açık Opt-in
Aşağıdaki, Vue sürüm 3.3 ve altındaki sürümler için geçerlidir. Destek, Vue çekirdeği 3.4 ve üzeri ile kaldırılmıştır ve @vitejs/plugin-vue
5.0 ve üzeri ile kaldırılmıştır. Dönüştürmeyi kullanmaya devam etmeyi düşünüyorsanız, lütfen Vue Makroları ile geçiş yapın.
Vite
@vitejs/plugin-vue@>=2.0.0
gerektirir- SFC'ler ve js(x)/ts(x) dosyalarına uygulanır. Dönüşüm uygulanmadan önce dosyalar üzerinde hızlı bir kullanım kontrolü yapılır, bu nedenle makroları kullanmayan dosyalar için performans maliyeti olmamalıdır.
reactivityTransform
artıkscript.refSugar
olarak iç içe geçmek yerine eklenti kök düzeyinde bir seçenek olduğundan, yalnızca SFC'leri etkilemez.
// vite.config.js
export default {
plugins: [
vue({
reactivityTransform: true
})
]
}
vue-cli
- Mevcut durumda yalnızca SFC'leri etkiler
vue-loader@>=17.0.0
gerektirir
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.module
.rule('vue')
.use('vue-loader')
.tap((options) => {
return {
...options,
reactivityTransform: true
}
})
}
}
Düz webpack
+ vue-loader
- Mevcut durumda yalnızca SFC'leri etkiler
vue-loader@>=17.0.0
gerektirir
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
reactivityTransform: true
}
}
]
}
}