# Basic Reactivity APIs
This section uses single-file component syntax for code examples
# reactive
Returns a reactive copy of the object.
const obj = reactive({ count: 0 })
The reactive conversion is "deep"—it affects all nested properties. In the ES2015 Proxy (opens new window) based implementation, the returned proxy is not equal to the original object. It is recommended to work exclusively with the reactive proxy and avoid relying on the original object.
Typing:
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
Note
reactive
will unwrap all the deep refs, while maintaining the ref reactivity
const count = ref(1)
const obj = reactive({ count })
// ref will be unwrapped
console.log(obj.count === count.value) // true
// it will update `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2
// it will also update `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Important
When assigning a ref to a reactive
property, that ref will be automatically unwrapped.
const count = ref(1)
const obj = reactive({})
obj.count = count
console.log(obj.count) // 1
console.log(obj.count === count.value) // true
2
3
4
5
6
7
# readonly
Takes an object (reactive or plain) or a ref and returns a readonly proxy to the original. A readonly proxy is deep: any nested property accessed will be readonly as well.
const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => {
// works for reactivity tracking
console.log(copy.count)
})
// mutating original will trigger watchers relying on the copy
original.count++
// mutating the copy will fail and result in a warning
copy.count++ // warning!
2
3
4
5
6
7
8
9
10
11
12
13
14
As with reactive
, if any property uses a ref
it will be automatically unwrapped when it is accessed via the proxy:
const raw = {
count: ref(123)
}
const copy = readonly(raw)
console.log(raw.count.value) // 123
console.log(copy.count) // 123
2
3
4
5
6
7
8
# isProxy
Checks if an object is a proxy created by reactive
or readonly
.
# isReactive
Checks if an object is a reactive proxy created by reactive
.
import { reactive, isReactive } from 'vue'
export default {
setup() {
const state = reactive({
name: 'John'
})
console.log(isReactive(state)) // -> true
}
}
2
3
4
5
6
7
8
9
It also returns true
if the proxy is created by readonly
, but is wrapping another proxy created by reactive
.
import { reactive, isReactive, readonly } from 'vue'
export default {
setup() {
const state = reactive({
name: 'John'
})
// readonly proxy created from plain object
const plain = readonly({
name: 'Mary'
})
console.log(isReactive(plain)) // -> false
// readonly proxy created from reactive proxy
const stateCopy = readonly(state)
console.log(isReactive(stateCopy)) // -> true
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# isReadonly
Checks if an object is a readonly proxy created by readonly
.
# toRaw
Returns the raw, original object of a reactive
or readonly
proxy. This is an escape hatch that can be used to temporarily read without incurring proxy access/tracking overhead or write without triggering changes. It is not recommended to hold a persistent reference to the original object. Use with caution.
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
2
3
4
# markRaw
Marks an object so that it will never be converted to a proxy. Returns the object itself.
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// also works when nested inside other reactive objects
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
2
3
4
5
6
WARNING
markRaw
and the shallowXXX APIs below allow you to selectively opt-out of the default deep reactive/readonly conversion and embed raw, non-proxied objects in your state graph. They can be used for various reasons:
Some values simply should not be made reactive, for example a complex 3rd party class instance, or a Vue component object.
Skipping proxy conversion can provide performance improvements when rendering large lists with immutable data sources.
They are considered advanced because the raw opt-out is only at the root level, so if you set a nested, non-marked raw object into a reactive object and then access it again, you get the proxied version back. This can lead to identity hazards - i.e. performing an operation that relies on object identity but using both the raw and the proxied version of the same object:
const foo = markRaw({
nested: {}
})
const bar = reactive({
// although `foo` is marked as raw, foo.nested is not.
nested: foo.nested
})
console.log(foo.nested === bar.nested) // false
2
3
4
5
6
7
8
9
10
Identity hazards are in general rare. However, to properly utilize these APIs while safely avoiding identity hazards requires a solid understanding of how the reactivity system works.
# shallowReactive
Creates a reactive proxy that tracks reactivity of its own properties but does not perform deep reactive conversion of nested objects (exposes raw values).
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
// mutating state's own properties is reactive
state.foo++
// ...but does not convert nested objects
isReactive(state.nested) // false
state.nested.bar++ // non-reactive
2
3
4
5
6
7
8
9
10
11
12
Unlike reactive
, any property that uses a ref
will not be automatically unwrapped by the proxy.
# shallowReadonly
Creates a proxy that makes its own properties readonly, but does not perform deep readonly conversion of nested objects (exposes raw values).
const state = shallowReadonly({
foo: 1,
nested: {
bar: 2
}
})
// mutating state's own properties will fail
state.foo++
// ...but works on nested objects
isReadonly(state.nested) // false
state.nested.bar++ // works
2
3
4
5
6
7
8
9
10
11
12
Unlike readonly
, any property that uses a ref
will not be automatically unwrapped by the proxy.