Ana içeriğe geç

Reaktivite Dönüştürme

Reaktivite Dönüştürme

Kaldırılan Deneysel Özellik

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.

Composition-API'ye Özgü

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 mevcutdefineProps()` kullanımında iki acı noktası bulunmaktadır:

  1. .value gibi, reaktiviteyi korumak için props.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.

  2. 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çin withDefaults() 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

Artık çekirdekte desteklenmiyor

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ık script.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
}
}
]
}
}