Reactivity API: Core
Zobacz także
Aby lepiej zrozumieć interfejsy API Reactivity, zaleca się przeczytanie następujących rozdziałów przewodnika:
- Fundamenty reaktywności (z preferencją API ustawioną na Composition API)
- Reaktywność w głębi
ref()
Przyjmuje wartość wewnętrzną i zwraca reaktywny i mutowalny obiekt ref, który posiada pojedynczą właściwość .value
, która wskazuje na wartość wewnętrzną.
Typ
tsfunction ref<T>(value: T): Ref<UnwrapRef<T>> interface Ref<T> { value: T }
Szczegóły
Obiekt ref jest mutowalny - tzn. można przypisywać nowe wartości do
.value
. Jest również reaktywny - tzn. wszelkie operacje odczytu do.value
są śledzone, a operacje zapisu wywołają powiązane efekty.Jeśli obiekt jest przypisany jako wartość ref, obiekt staje się głęboko reaktywny za pomocą reactive(). Oznacza to również, że jeśli obiekt zawiera zagnieżdżone referencje, zostaną one głęboko rozpakowane.
Aby uniknąć głębokiej konwersji, należy użyć
shallowRef()
.Przykład
jsconst count = ref(0) console.log(count.value) // 0 count.value = 1 console.log(count.value) // 1
Zobacz również
- Poradnik - Podstawy reaktywności z
ref()
- Poradnik - Wpisywanie
ref()
<sup class=„vt-badge ts” />
- Poradnik - Podstawy reaktywności z
computed()
Używa funkcji getter i zwraca reaktywny obiekt ref tylko do odczytu dla wartości zwróconej z funkcji getter. Może również przyjąć obiekt z funkcjami get
i set
, aby utworzyć zapisywalny obiekt ref.
Type
ts// tylko do odczytu function computed<T>( getter: (oldValue: T | undefined) => T, // Zobacz link „Computed Debugging" poniżej debuggerOptions?: DebuggerOptions ): Readonly<Ref<Readonly<T>>> // użycie również do zapisu function computed<T>( options: { get: (oldValue: T | undefined) => T set: (value: T) => void }, debuggerOptions?: DebuggerOptions ): Ref<T>
Przykład
Tworzenie wyliczanego wskaźnika tylko do odczytu:
jsconst count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // error
Tworzenie zapisywalnego obliczonego ref:
jsconst count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0
Debugowanie:
jsconst plusOne = computed(() => count.value + 1, { onTrack(e) { debugger }, onTrigger(e) { debugger } })
Zobacz również
- Przewodnik - Właściwości obliczane
- Przewodnik - Debugowanie obliczeniowe
- Przewodnik - Wpisywanie
computed()
<sup class=„vt-badge ts” /> - Przewodnik - Wydajność - Stabilność obliczeniowa <sup class=„vt-badge” data-text="3.4+” />
reactive()
Zwraca reaktywne proxy obiektu.
Typ
tsfunction reactive<T extends object>(target: T): UnwrapNestedRefs<T>
Szczegóły
Konwersja reaktywna jest „głęboka”: wpływa na wszystkie zagnieżdżone właściwości. Obiekt reaktywny również głęboko rozpakowuje wszelkie właściwości, które są refs, zachowując reaktywność.
Należy również zauważyć, że nie jest wykonywane rozpakowywanie ref, gdy ref jest dostępny jako element reaktywnej tablicy lub natywnego typu kolekcji, takiego jak
Map
.Aby uniknąć głębokiej konwersji i zachować reaktywność tylko na poziomie korzenia, należy zamiast tego użyć shallowReactive().
Zwrócony obiekt i jego zagnieżdżone obiekty są opakowane w ES Proxy i nie są równe oryginalnym obiektom. Zaleca się pracę wyłącznie z reaktywnym proxy i unikanie polegania na oryginalnym obiekcie.
Przykład
Tworzenie obiektu reaktywnego:
jsconst obj = reactive({ count: 0 }) obj.count++
Rozpakowywanie ref:
tsconst count = ref(1) const obj = reactive({ count }) // ref zostanie rozpakowany console.log(obj.count === count.value) // true // to zaktualizuje `obj.count` count.value++ console.log(count.value) // 2 console.log(obj.count) // 2 // zaktualizuje również `count` ref obj.count++ console.log(obj.count) // 3 console.log(count.value) // 3
Należy pamiętać, że referencje nie są rozpakowywane, gdy są dostępne jako elementy tablicy lub kolekcji:
jsconst books = reactive([ref('Vue 3 Guide')]) // .value jest tutaj potrzebne console.log(books[0].value) const map = reactive(new Map([['count', ref(0)]])) // .value jest tutaj potrzebne console.log(map.get('count').value)
Podczas przypisywania ref do właściwości
reactive
, ten ref również zostanie automatycznie rozpakowany:tsconst count = ref(1) const obj = reactive({}) obj.count = count console.log(obj.count) // 1 console.log(obj.count === count.value) // true
Zobacz również
readonly()
Pobiera obiekt (reaktywny lub zwykły) lub ref i zwraca tylko do odczytu proxy do oryginału.
Typ
tsfunction readonly<T extends object>( target: T ): DeepReadonly<UnwrapNestedRefs<T>>
Szczegóły
Proxy tylko do odczytu jest głębokie: każda zagnieżdżona właściwość, do której uzyskano dostęp, będzie również tylko do odczytu. Ma również takie samo zachowanie ref-unwrapping jak
reactive()
, z wyjątkiem tego, że rozpakowane wartości będą również tylko do odczytu.Aby uniknąć głębokiej konwersji, należy użyć shallowReadonly().
Przykład
jsconst original = reactive({ count: 0 }) const copy = readonly(original) watchEffect(() => { // działa do śledzenia reaktywności console.log(copy.count) }) // zmutowanie oryginału spowoduje uruchomienie obserwatorów polegających na kopii original.count++ // zmutowanie kopii nie powiedzie się i spowoduje wyświetlenie ostrzeżenia copy.count++ // ostrzeżenie!
watchEffect()
Natychmiast uruchamia funkcję, jednocześnie reaktywnie śledząc jej zależności i uruchamia ją ponownie, gdy zależności ulegną zmianie.
Typ
tsfunction watchEffect( effect: (onCleanup: OnCleanup) => void, options?: WatchEffectOptions ): StopHandle type OnCleanup = (cleanupFn: () => void) => void interface WatchEffectOptions { flush?: 'pre' | 'post' | 'sync' // default: 'pre' onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void } type StopHandle = () => void
Sczegóły
Pierwszym argumentem jest funkcja efektu, która ma zostać uruchomiona. Funkcja efektu otrzymuje funkcję, która może być użyta do zarejestrowania wywołania zwrotnego czyszczenia. Wywołanie zwrotne czyszczenia zostanie wywołane tuż przed następnym ponownym uruchomieniem efektu i może zostać użyte do wyczyszczenia unieważnionych efektów ubocznych, np. oczekującego żądania asynchronicznego (patrz przykład poniżej).
Drugim argumentem jest opcjonalny obiekt opcji, który może być użyty do dostosowania czasu spłukiwania efektu lub do debugowania zależności efektu.
Domyślnie obserwatorzy będą uruchamiani tuż przed renderowaniem komponentu. Ustawienie
flush: 'post'
spowoduje odroczenie obserwatora do czasu po renderowaniu komponentu. Więcej informacji można znaleźć w Callback Flush Timing. W rzadkich przypadkach może być konieczne natychmiastowe uruchomienie obserwatora, gdy zmieni się zależność reaktywna, np. w celu unieważnienia pamięci podręcznej. Można to osiągnąć używającflush: 'sync'
. Ustawienie to powinno być jednak używane ostrożnie, ponieważ może prowadzić do problemów z wydajnością i spójnością danych, jeśli wiele właściwości jest aktualizowanych w tym samym czasie.Wartością zwrotną jest funkcja uchwytu, którą można wywołać w celu zatrzymania ponownego działania efektu.
Przykład
jsconst count = ref(0) watchEffect(() => console.log(count.value)) // -> logs 0 count.value++ // -> logs 1
Usuwanie skutków ubocznych:
jswatchEffect(async (onCleanup) => { const { response, cancel } = doAsyncWork(id.value) // `cancel` zostanie wywołane jeśli `id` ulegnie zmianie // poprzednie oczekujące żądanie zostanie anulowane // jeśli nie zostało jeszcze zakończone onCleanup(cancel) data.value = await response })
Zatrzymanie obserwatora:
jsconst stop = watchEffect(() => {}) // gdy obserwator nie jest już potrzebny: stop()
Opcje:
jswatchEffect(() => {}, { flush: 'post', onTrack(e) { debugger }, onTrigger(e) { debugger } })
Zobacz również
watchPostEffect()
Alias watchEffect()
z opcją flush: 'post'
.
watchSyncEffect()
Alias watchEffect()
z opcją flush: 'sync'
.
watch()
Obserwuje jedno lub więcej reaktywnych źródeł danych i wywołuje funkcję zwrotną, gdy źródła te ulegną zmianie.
Typ
ts// obserwowanie pojedynczego źródła function watch<T>( source: WatchSource<T>, callback: WatchCallback<T>, options?: WatchOptions ): StopHandle // obserwowanie wielu źródeł function watch<T>( sources: WatchSource<T>[], callback: WatchCallback<T[]>, options?: WatchOptions ): StopHandle type WatchCallback<T> = ( value: T, oldValue: T, onCleanup: (cleanupFn: () => void) => void ) => void type WatchSource<T> = | Ref<T> // ref | (() => T) // getter | T extends object ? T : never // reactive object interface WatchOptions extends WatchEffectOptions { immediate?: boolean // default: false deep?: boolean // default: false flush?: 'pre' | 'post' | 'sync' // default: 'pre' onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void once?: boolean // default: false (3.4+) }
Typy są uproszczone dla czytelności.
Szczegóły
Funkcja
watch()
jest domyślnie lazy - tzn. wywołanie zwrotne jest wywoływane tylko wtedy, gdy obserwowane źródło uległo zmianie.Pierwszym argumentem jest źródło obserwatora. Źródło może być jednym z poniższych:
- Funkcja getter zwracająca wartość
- Ref
- Obiekt reaktywny
- ...lub tablicą powyższych.
Drugim argumentem jest wywołanie zwrotne, które zostanie wywołane po zmianie źródła. Wywołanie zwrotne otrzymuje trzy argumenty: nową wartość, starą wartość i funkcję rejestrującą wywołanie zwrotne czyszczenia efektu ubocznego. Wywołanie zwrotne czyszczenia zostanie wywołane tuż przed następnym ponownym uruchomieniem efektu i może być użyte do wyczyszczenia unieważnionych efektów ubocznych, np. oczekującego żądania asynchronicznego.
Podczas oglądania wielu źródeł, wywołanie zwrotne otrzymuje dwie tablice zawierające nowe / stare wartości odpowiadające tablicy źródłowej.
Trzecim opcjonalnym argumentem jest obiekt opcji, który obsługuje następujące opcje:
immediate
: wywołanie zwrotne natychmiast po utworzeniu obserwatora. Stara wartość będzie „niezdefiniowana” przy pierwszym wywołaniu.deep
: wymusza głębokie przeszukiwanie źródła, jeśli jest ono obiektem, tak aby wywołanie zwrotne było uruchamiane przy głębokich mutacjach. Zobacz Deep Watchers.flush
: dostosowuje czas spłukiwania wywołania zwrotnego. Zobacz Callback Flush Timing iwatchEffect()
.onTrack / onTrigger
: debugowanie zależności watchera. Zobacz Watcher Debugging.once
: uruchamia wywołanie zwrotne tylko raz. Obserwator jest automatycznie zatrzymywany po pierwszym uruchomieniu wywołania zwrotnego. <sup class=„vt-badge” data-text="3.4+” />
W porównaniu do
watchEffect()
,watch()
pozwala nam na:- Leniwe wykonywanie efektu ubocznego;
- Bardziej szczegółowe określenie, jaki stan powinien wyzwalać ponowne uruchomienie obserwatora;
- Dostęp zarówno do poprzedniej, jak i bieżącej wartości obserwowanego stanu.
Przykład
Obserwowanie gettera:
jsconst state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { /* ... */ } )
Obserwowanie ref:
jsconst count = ref(0) watch(count, (count, prevCount) => { /* ... */ })
Podczas obserwowania wielu źródeł, wywołanie zwrotne otrzymuje tablice zawierające nowe/stare wartości odpowiadające tablicy źródłowej:
jswatch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })
Podczas korzystania ze źródła gettera, watcher uruchamia się tylko wtedy, gdy wartość zwracana gettera uległa zmianie. Jeśli chcesz, aby wywołanie zwrotne było uruchamiane nawet w przypadku głębokich mutacji, musisz jawnie wymusić przejście obserwatora w tryb głęboki za pomocą
{ deep: true }
. W trybie głębokim nowa i stara wartość będą tym samym obiektem, jeśli wywołanie zwrotne zostało wywołane przez głęboką mutację:jsconst state = reactive({ count: 0 }) watch( () => state, (newValue, oldValue) => { // newValue === oldValue }, { deep: true } )
Podczas bezpośredniego obserwowania obiektu reaktywnego, obserwator jest automatycznie w trybie głębokim:
jsconst state = reactive({ count: 0 }) watch(state, () => { /* triggers on deep mutation to state */ })
watch()
dzieli ten sam czas spłukiwania i opcje debugowania zwatchEffect()
:jswatch(source, callback, { flush: 'post', onTrack(e) { debugger }, onTrigger(e) { debugger } })
Zatrzymanie obserwatora:
jsconst stop = watch(source, callback) // gdy obserwator nie jest już potrzebny: stop()
Usuwanie skutków ubocznych:
jswatch(id, async (newId, oldId, onCleanup) => { const { response, cancel } = doAsyncWork(newId) // `cancel` zostanie wywołane, jeśli `id` ulegnie zmianie, anulując // poprzednie żądanie, jeśli nie zostało jeszcze zakończone onCleanup(cancel) data.value = await response })
Zobacz również