Reactivity API: Advanced
shallowRef()
Płytka wersja ref()
.
Typ
tsfunction shallowRef<T>(value: T): ShallowRef<T> interface ShallowRef<T> { value: T }
Szczegóły
W przeciwieństwie do
ref()
, wewnętrzna wartość płytkiego ref jest przechowywana i eksponowana tak jak jest, i nie będzie głęboko reaktywna. Tylko dostęp do.value
jest reaktywny.Funkcja
shallowRef()
jest zwykle używana do optymalizacji wydajności dużych struktur danych lub integracji z zewnętrznymi systemami zarządzania stanem.Przykład
jsconst state = shallowRef({ count: 1 }) // NIE powoduje zmiany state.value.count = 2 // powoduje zmiany state.value = { count: 2 }
Zobacz również
triggerRef()
Wymusza wyzwalanie efektów zależnych od shallow ref. Jest to zwykle używane po dokonaniu głębokich mutacji do wewnętrznej wartości płytkiej referencji.
Typ
tsfunction triggerRef(ref: ShallowRef): void
Przykład
jsconst shallow = shallowRef({ greet: 'Hello, world' }) // wyświetla „Hello, world” raz przy pierwszym uruchomieniu watchEffect(() => { console.log(shallow.value.greet) }) // Nie wywoła to efektu, ponieważ ref jest płytki shallow.value.greet = 'Hello, universe' // wyświetla „Witaj, wszechświecie” triggerRef(shallow)
customRef()
Tworzy niestandardowy ref z wyraźną kontrolą nad śledzeniem zależności i wyzwalaniem aktualizacji.
Typ
tsfunction customRef<T>(factory: CustomRefFactory<T>): Ref<T> type CustomRefFactory<T> = ( track: () => void, trigger: () => void ) => { get: () => T set: (value: T) => void }
Szczegóły
Funkcja
customRef()
oczekuje funkcji fabryki, która otrzymuje funkcjetrack
itrigger
jako argumenty i powinna zwrócić obiekt z metodamiget
iset
.Ogólnie rzecz biorąc,
track()
powinien być wywoływany wewnątrzget()
, atrigger()
powinien być wywoływany wewnątrzset()
. Jednakże, masz pełną kontrolę nad tym, kiedy powinny być one wywoływane lub czy w ogóle powinny być wywoływane.Przykład
Tworzenie debounced ref, który aktualizuje wartość dopiero po upływie określonego czasu od ostatniego wywołania set:
jsimport { customRef } from 'vue' export function useDebouncedRef(value, delay = 200) { let timeout return customRef((track, trigger) => { return { get() { track() return value }, set(newValue) { clearTimeout(timeout) timeout = setTimeout(() => { value = newValue trigger() }, delay) } } }) }
Użycie w komponencie:
vue<script setup> import { useDebouncedRef } from './debouncedRef' const text = useDebouncedRef('hello') </script> <template> <input v-model="text" /> </template>
Używaj z rozwagą
Używając customRef, powinniśmy zachować ostrożność co do wartości zwracanej przez jego getter, szczególnie podczas generowania nowych typów danych obiektów za każdym razem, gdy getter jest uruchamiany. Ma to wpływ na relację między komponentami nadrzędnymi i podrzędnymi, gdzie taki customRef został przekazany jako właściwość.
Funkcja renderowania komponentu nadrzędnego może zostać wywołana przez zmiany w innym stanie reaktywnym. Podczas ponownego renderowania wartość naszego customRef jest ponownie oceniana, zwracając nowy typ danych obiektu jako właściwość do komponentu podrzędnego. Ta właściwość jest porównywana z jej ostatnią wartością w komponencie potomnym, a ponieważ są one różne, zależności reaktywne customRef są uruchamiane w komponencie potomnym. W międzyczasie zależności reaktywne w komponencie nadrzędnym nie są uruchamiane, ponieważ setter customRef nie został wywołany, a jego zależności nie zostały w rezultacie uruchomione.
shallowReactive()
Płytka wersja reactive()
.
Typ
tsfunction shallowReactive<T extends object>(target: T): T
Szczegóły
W przeciwieństwie do
reactive()
, nie ma głębokiej konwersji: tylko właściwości na poziomie głównym są reaktywne dla płytkiego obiektu reaktywnego. Wartości właściwości są przechowywane i eksponowane tak jak są - oznacza to również, że właściwości z wartościami ref nie będą automatycznie rozpakowywane.Używaj z rozwagą
Płytkie struktury danych powinny być używane tylko dla stanu głównego komponentu. Unikaj zagnieżdżania ich wewnątrz głębokiego obiektu reaktywnego, ponieważ tworzy to drzewo z niespójnym zachowaniem reaktywności, które może być trudne do zrozumienia i debugowania.
Przykład
jsconst state = shallowReactive({ foo: 1, nested: { bar: 2 } }) // mutowanie własnych właściwości stanu jest reaktywne state.foo++ // ...ale nie konwertuje zagnieżdżonego obiektu isReactive(state.nested) // false // NIE reaktywny state.nested.bar++
shallowReadonly()
Płytka wersja readonly()
.
Typ
tsfunction shallowReadonly<T extends object>(target: T): Readonly<T>
Szczegóły
W przeciwieństwie do
readonly()
, nie ma głębokiej konwersji: tylko właściwości na poziomie głównym są tylko do odczytu. Wartości właściwości są przechowywane i eksponowane tak jak są - oznacza to również, że właściwości z wartościami ref nie będą automatycznie rozpakowywane.Używaj z rozwagą
Płytkie struktury danych powinny być używane tylko dla stanu głównego komponentu. Unikaj zagnieżdżania ich wewnątrz głębokiego obiektu reaktywnego, ponieważ tworzy to drzewo z niespójnym zachowaniem reaktywności, które może być trudne do zrozumienia i debugowania.
Przykład
jsconst state = shallowReadonly({ foo: 1, nested: { bar: 2 } }) // mutowanie własnych właściwości stanu nie powiedzie się state.foo++ // ...ale działa na obiektach zagnieżdżonych isReadonly(state.nested) // false // zadziała state.nested.bar++
toRaw()
Zwraca nieprzetworzony, oryginalny obiekt proxy utworzony przez Vue.
Typ
tsfunction toRaw<T>(proxy: T): T
Szczegóły
Funkcja
toRaw()
może zwrócić oryginalny obiekt z proxy utworzony przezreactive()
,readonly()
,shallowReactive()
lubshallowReadonly()
.Jest to wyjście, które można użyć do tymczasowego odczytu bez ponoszenia kosztów dostępu / śledzenia proxy lub zapisu bez wywoływania zmian. Nie zaleca się utrzymywania trwałego odniesienia do oryginalnego obiektu. Należy zachować ostrożność.
Przykład
jsconst foo = {} const reactiveFoo = reactive(foo) console.log(toRaw(reactiveFoo) === foo) // true
markRaw()
Zaznacza obiekt, aby nigdy nie został przekonwertowany na proxy. Zwraca sam obiekt.
Typ
tsfunction markRaw<T extends object>(value: T): T
Przykład
jsconst foo = markRaw({}) console.log(isReactive(reactive(foo))) // false // działa również po zagnieżdżeniu wewnątrz innych obiektów reaktywnych const bar = reactive({ foo }) console.log(isReactive(bar.foo)) // false
Używaj z ostrożnością
markRaw()
i płytkie API takie jakshallowReactive()
pozwalają na selektywną rezygnację z domyślnej głębokiej konwersji reactive/readonly i osadzenie surowych, nieproxowanych obiektów w grafie stanu. Mogą one być używane z różnych powodów:Niektóre wartości po prostu nie powinny być reaktywne, na przykład złożona instancja klasy zewnętrznej bibloteki lub obiekt komponentu Vue.
Pominięcie konwersji proxy może zapewnić poprawę wydajności podczas renderowania dużych list z niezmiennymi źródłami danych.
Są one uważane za zaawansowane, ponieważ surowa rezygnacja jest tylko na poziomie głównym, więc jeśli ustawisz zagnieżdżony, nieoznaczony obiekt surowy w obiekcie reaktywnym, a następnie ponownie uzyskasz do niego dostęp, otrzymasz z powrotem wersję proxy. Może to prowadzić do zagrożeń tożsamości - tj. wykonywania operacji, która opiera się na tożsamości obiektu, ale przy użyciu zarówno nieprzetworzonej, jak i proxy wersji tego samego obiektu:
jsconst foo = markRaw({ nested: {} }) const bar = reactive({ // chociaż `foo` jest oznaczone jako surowe, foo.nested nie jest. nested: foo.nested }) console.log(foo.nested === bar.nested) // false
Zagrożenia związane z tożsamością są generalnie rzadkie. Jednak prawidłowe wykorzystanie tych interfejsów API przy jednoczesnym bezpiecznym unikaniu zagrożeń związanych z tożsamością wymaga solidnego zrozumienia sposobu działania systemu reaktywności.
effectScope()
Tworzy obiekt zakresu efektu, który może przechwytywać efekty reaktywne (tj. obliczone i obserwujące) utworzone w nim, dzięki czemu efekty te mogą być usuwane razem. Szczegółowe przypadki użycia tego interfejsu API można znaleźć w odpowiednim dokumencie RFC.
Typ
tsfunction effectScope(detached?: boolean): EffectScope interface EffectScope { run<T>(fn: () => T): T | undefined // undefined jeśli zakres jest nieaktywny stop(): void }
Przykład
jsconst scope = effectScope() scope.run(() => { const doubled = computed(() => counter.value * 2) watch(doubled, () => console.log(doubled.value)) watchEffect(() => console.log('Count: ', doubled.value)) }) // aby usunąć wszystkie efekty w zakresie scope.stop()
getCurrentScope()
Zwraca bieżący aktywny zakres efektów, jeśli taki istnieje.
Typ
tsfunction getCurrentScope(): EffectScope | undefined
onScopeDispose()
Rejestruje wywołanie zwrotne usuwania dla bieżącego aktywnego [zakresu efektów] (#effectscope). Wywołanie zwrotne zostanie wywołane, gdy powiązany zakres efektów zostanie zatrzymany.
Metoda ta może być używana jako niepowiązana z komponentem zamiana onUnmounted
w funkcjach composable wielokrotnego użytku, ponieważ funkcja setup()
każdego komponentu Vue jest również wywoływana w zakresie efektu.
Typ
tsfunction onScopeDispose(fn: () => void): void