# Реактивные ref-ссылки
В этом разделе в примерах кода используется синтаксис однофайловых компонентов
# ref
Получает внутреннее значение и возвращает реактивный и мутируемый ref-объект. В этом ref-объекте есть только одно свойство .value
, которое указывает на внутреннее значение.
Пример:
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
2
3
4
5
Если свойству value
ref-ссылки передаётся объект, то объект становится глубоко реактивным с помощью функции reactive.
Типизация:
interface Ref<T> {
value: T
}
function ref<T>(value: T): Ref<T>
2
3
4
5
Если потребуется определить сложный тип для внутреннего значения ref-ссылки, то это реализуется передачей дженерика аргументом при вызове ref
для переопределения вывода типа по умолчанию:
const foo = ref<string | number>('foo') // тип foo: Ref<string | number>
foo.value = 123 // ok!
2
3
Когда тип дженерика неизвестен, рекомендуется приводить ref
к Ref<T>
:
function useState<State extends string>(initial: State) {
const state = ref(initial) as Ref<State> // state.value -> State extends string
return state
}
2
3
4
# unref
Возвращает внутреннее значение, если аргумент является ref
, в противном случае — сам аргумент. Это всего лишь синтаксический сахар для val = isRef(val) ? val.value : val
.
function useFoo(x: number | Ref<number>) {
const unwrapped = unref(x) // значение unwrapped гарантированно будет числом
}
2
3
# toRef
Можно использоваться для создания ref
для свойства на исходном реактивном объекте. После можно передавать ref-ссылку, сохраняя реактивную связь с исходным свойством.
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
fooRef.value++
console.log(state.foo) // 2
state.foo++
console.log(fooRef.value) // 3
2
3
4
5
6
7
8
9
10
11
12
toRef
пригодится при передаче ref-ссылки из входного параметра в функцию композиции:
export default {
setup(props) {
useSomeFeature(toRef(props, 'foo'))
}
}
2
3
4
5
toRef
возвращает ref-ссылку пригодную для использования, даже если на данный момент свойства в источнике не существует. Это особенно полезно при работе с необязательными входными параметрами, которые не будут подхвачены toRefs
.
# toRefs
Преобразует реактивный объект в обычный объект, в котором каждое свойство будет ref
, указывающей на соответствующее свойство исходного объекта.
const state = reactive({
foo: 1,
bar: 2
})
const stateAsRefs = toRefs(state)
/*
Тип stateAsRefs будет:
{
foo: Ref<number>,
bar: Ref<number>
}
*/
// Реактивная ref-ссылка и оригинальное свойство «связаны»
state.foo++
console.log(stateAsRefs.foo.value) // 2
stateAsRefs.foo.value++
console.log(state.foo) // 3
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
toRefs
полезен при возвращении реактивного объекта из функции композиции, чтобы в компоненте использовать деструктуризацию/оператор разложения к возвращаемому объекту без потери реактивности:
function useFeatureX() {
const state = reactive({
foo: 1,
bar: 2
})
// логика, работающая с состоянием
// преобразуем к refs при возвращении результата
return toRefs(state)
}
export default {
setup() {
// теперь можно использовать деструктуризацию без потери реактивности
const { foo, bar } = useFeatureX()
return {
foo,
bar
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
toRefs
будет генерировать ref-ссылки только для тех свойств, которые были в исходном объекте. Для создания ref-ссылки для конкретного свойства следует использовать toRef
.
# isRef
Проверяет является ли значение ref-объектом.
# customRef
Создаёт пользовательскую ref-ссылку с возможностью явно контролировать отслеживание зависимостей и управлять вызовом обновлений. Ожидает функцию-фабрику, получающую аргументами функции track
и trigger
, и возвращающую объект с get
и set
.
Пример пользовательской ref-ссылки для реализации debounce вместе с v-model
:
<input v-model="text" />
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)
}
}
})
}
export default {
setup() {
return {
text: useDebouncedRef('hello')
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Типизация:
function customRef<T>(factory: CustomRefFactory<T>): Ref<T>
type CustomRefFactory<T> = (
track: () => void,
trigger: () => void
) => {
get: () => T
set: (value: T) => void
}
2
3
4
5
6
7
8
9
# shallowRef
Создание ref-ссылки, которая отслеживает изменение своего .value
, но не делает это значение реактивным.
const foo = shallowRef({})
// изменение значения ref-ссылки реактивно
foo.value = {}
// но значение НЕ ПРЕОБРАЗУЕТСЯ в реактивное.
isReactive(foo.value) // false
2
3
4
5
См. также: Создание автономных ссылок на реактивные значения
# triggerRef
Выполняет любые эффекты, привязанные вручную к shallowRef
.
const shallow = shallowRef({
greet: 'Привет, мир'
})
// Выведет "Привет, мир" один раз при первом проходе
watchEffect(() => {
console.log(shallow.value.greet)
})
// Это не вызовет эффект, потому что ref-ссылка неглубокая
shallow.value.greet = 'Привет, вселенная'
// Выведет "Привет, вселенная"
triggerRef(shallow)
2
3
4
5
6
7
8
9
10
11
12
13
14
См. также: Вычисляемые свойства и методы-наблюдатели — watchEffect