Reactivity API: Дополнительно
shallowRef()
Неглубокая версия ref()
.
Тип
tsfunction shallowRef<T>(value: T): ShallowRef<T> interface ShallowRef<T> { value: T }
Подробности
В отличие от
ref()
, внутреннее значение неглубокой ссылки хранится и раскрывается как есть, и не может быть сделано глубоко реактивным. Только доступ к.value
является реактивным.shallowRef()
обычно используется для оптимизации производительности больших структур данных или интеграции с внешними системами управления состоянием.Пример
jsconst state = shallowRef({ count: 1 }) // не вызывает изменений state.value.count = 2 // вызывает изменения state.value = { count: 2 }
Смотрите также
triggerRef()
Принудительный запуск эффектов, зависящих от shallow ref. Обычно это используется после выполнения глубоких мутаций к внутреннему значению неглубокой ссылки.
Тип
tsfunction triggerRef(ref: ShallowRef): void
Пример
jsconst shallow = shallowRef({ greet: 'Привет, мир' }) // Логирует "Привет, мир" один раз во время первого прогона watchEffect(() => { console.log(shallow.value.greet) }) // Это не вызовет эффекта, потому что ссылка неглубокая shallow.value.greet = 'Привет, Вселенная' // Логирует "Привет, Вселенная" triggerRef(shallow)
customRef()
Создает настраиваемую ссылку с явным контролем над отслеживанием зависимостей и срабатыванием обновлений.
Тип
tsfunction customRef<T>(factory: CustomRefFactory<T>): Ref<T> type CustomRefFactory<T> = ( track: () => void, trigger: () => void ) => { get: () => T set: (value: T) => void }
Подробности
customRef()
ожидает фабричную функцию, которая получает в качестве аргументов функцииtrack
иtrigger
и должна возвращать объект с методамиget
иset
.В общем случае,
track()
следует вызывать внутриget()
, аtrigger()
— внутриset()
. Однако вы полностью контролируете, когда их следует вызывать и следует ли вообще.Пример
Создание отложенной ссылки, которая обновляет значение только через определённый промежуток времени после последнего вызова
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) } } }) }
Использование в компоненте:
vue<script setup> import { useDebouncedRef } from './debouncedRef' const text = useDebouncedRef('hello') </script> <template> <input v-model="text" /> </template>
Используйте с осторожностью
При использовании
customRef
следует с осторожностью относиться к возвращаемому значению его геттера, особенно при генерации новых типов данных объектов при каждом запуске геттера. Это влияет на отношения между родительскими и дочерними компонентами, где такойcustomRef
был передан в качестве параметра.Функция рендеринга родительского компонента может быть вызвана изменениями в другом реактивном состоянии. Во время рендеринга значение нашего
customRef
анализируется, возвращая новый тип данных объекта в качестве параметра дочернего компонента. Этот параметр сравнивается с его последним значением в дочернем компоненте, и поскольку они отличаются, в дочернем компоненте срабатывают реактивные зависимостиcustomRef
. Тем временем реактивные зависимости в родительском компоненте не выполняются, потому что сеттерcustomRef
не был вызван, и его зависимости в результате не срабатывают.
shallowReactive()
Неглубокая версия reactive()
.
Тип
tsfunction shallowReactive<T extends object>(target: T): T
Подробности
В отличие от
reactive()
, здесь нет глубокого преобразования: для неглубокого реактивного объекта реактивными являются только свойства корневого уровня. Значения свойств хранятся и раскрываются как есть — это также означает, что свойства с ref-значениями НЕ будут автоматически разворачиваться.Используйте с осторожностью
Неглубокие структуры данных следует использовать только для состояния корневого уровня компонента. Избегайте вложения его внутрь глубокого реактивного объекта, так как это создаст дерево с непоследовательным поведением реактивности, которое может быть трудно понять и отладить.
Пример
jsconst state = shallowReactive({ foo: 1, nested: { bar: 2 } }) // Мутация собственных свойств состояния является реактивной state.foo++ // ...но не преобразует вложенные объекты isReactive(state.nested) // false // НЕ реактивная state.nested.bar++
shallowReadonly()
Неглубокая версия readonly()
.
Тип
tsfunction shallowReadonly<T extends object>(target: T): Readonly<T>
Подробности
В отличие от
readonly()
, здесь нет глубокого преобразования: только свойства корневого уровня становятся доступными для чтения. Значения свойств хранятся и раскрываются как есть — это также означает, что свойства с ref-значениями НЕ будут автоматически разворачиваться.Используйте с осторожностью
Неглубокие структуры данных следует использовать только для состояния корневого уровня компонента. Избегайте вложения его внутрь глубокого реактивного объекта, так как это создаст дерево с непоследовательным поведением реактивности, которое может быть трудно понять и отладить.
Пример
jsconst state = shallowReadonly({ foo: 1, nested: { bar: 2 } }) // Мутация собственных свойств состояния будет неудачной state.foo++ // ...но работает на вложенных объектах isReadonly(state.nested) // false // работает state.nested.bar++
toRaw()
Возвращает исходный объект прокси, созданного во Vue.
Тип
tsfunction toRaw<T>(proxy: T): T
Подробности
toRaw()
может возвращать исходный объект из прокси, созданных с помощьюreactive()
,readonly()
,shallowReactive()
илиshallowReadonly()
.Это аварийный люк, который можно использовать для временного чтения без накладных расходов на доступ к прокси/отслеживание или записи без запуска изменений. Не рекомендуется хранить постоянную ссылку на исходный объект. Используйте с осторожностью.
Пример
jsconst foo = {} const reactiveFoo = reactive(foo) console.log(toRaw(reactiveFoo) === foo) // true
markRaw()
Помечает объект так, что он никогда не будет преобразован в прокси. Возвращает сам объект.
Тип
tsfunction markRaw<T extends object>(value: T): T
Пример
jsconst foo = markRaw({}) console.log(isReactive(reactive(foo))) // false // также работает при вложении внутри других реактивных объектов const bar = reactive({ foo }) console.log(isReactive(bar.foo)) // false
Используйте с осторожностью
markRaw()
и поверхностные API, такие какshallowReactive()
, позволяют выборочно отказаться от стандартного глубокого преобразования reactive/readonly и внедрить необработанные, непроксированные объекты в ваш граф состояний. Они могут использоваться по разным причинам:Некоторые значения просто не должны быть реактивными, например, сложные экземпляры классов сторонних производителей или объекты компонентов Vue.
Отсутствие преобразования прокси может повысить производительность при отрисовке больших списков с неизменяемыми источниками данных.
Они считаются продвинутыми, потому что отказ от raw происходит только на корневом уровне, поэтому если вы поместите вложенный немаркированный raw-объект в reactive-объект, а затем снова обратитесь к нему, то получите обратно проксированную версию. Это может привести к опасности идентичности — т. е. выполнение операции, основанной на идентификации объекта, но использующей как исходную, так и проксированную версию одного и того же объекта:
jsconst foo = markRaw({ nested: {} }) const bar = reactive({ // Хотя `foo` помечен как raw, foo.nested не помечен. nested: foo.nested }) console.log(foo.nested === bar.nested) // false
Опасности, связанные с личными данными, как правило, встречаются редко. Однако для правильного использования этих API и безопасного предотвращения угроз идентификации требуется четкое понимание того, как работает система реактивности.
effectScope()
Создает объект области видимости эффектов, который может захватывать реактивные эффекты (т. е. вычисляемые свойства и наблюдатели), созданные внутри него, чтобы эти эффекты можно было утилизировать вместе. Подробные примеры использования этого API можно найти в соответствующем RFC.
Тип
tsfunction effectScope(detached?: boolean): EffectScope interface EffectScope { run<T>(fn: () => T): T | undefined // undefined, если область видимости неактивна stop(): void }
Пример
jsconst scope = effectScope() scope.run(() => { const doubled = computed(() => counter.value * 2) watch(doubled, () => console.log(doubled.value)) watchEffect(() => console.log('Счётчик: ', doubled.value)) }) // избавляемся от всех эффектов в области действия scope.stop()
getCurrentScope()
Возвращает текущую активную область действия, если таковая имеется.
Тип
tsfunction getCurrentScope(): EffectScope | undefined
onScopeDispose()
Регистрирует обратный вызов dispose для текущей активной области действия. Обратный вызов будет вызван, когда связанная область действия будет остановлена.
Этот метод можно использовать как не связанную с компонентами замену onUnmounted
в многократно используемых функциях композиции, поскольку функция setup()
каждого компонента Vue также вызывается в области видимости эффекта.
Если эта функция будет вызвана без активной области действия, будет выдано предупреждение. В версии 3.5+ это предупреждение можно подавить, передав true
в качестве второго аргумента.
Тип
tsfunction onScopeDispose(fn: () => void, failSilently?: boolean): void