Reactivity is an essential part of Vue. We use ref
to create a Reactive Reference of value.
Version
Vue 3.2
ref
Use ref
to implement the classical counter.
<script setup>
import { ref } from 'vue'
let count = ref (0)
let onClick = () => count.value++
</script>
<template>
<button @click="onClick">+</button> {{ count }}
</template>
Line 4
let count = ref (0)
Use ref
to define count
Reactive Reference with default value 0
.
第 5 行
let onClick = () => count.value++
- We have to use
.value
to read the value from Reactive Reference - We have to use
.value
to write a value to Reactive Reference
Point-free
Use Point-free style to deal with Reactive Reference.
<script setup>
import { ref } from 'vue'
import { read, write } from 'vue3-fp'
import { pipe, inc } from 'ramda'
let count = ref (0)
let onClick = pipe (
read (count),
inc,
write (count)
)
</script>
<template>
<button @click="onClick">+</button>{{ count }}
</template>
Line 6
let count = ref (0)
Use ref
to define count
Reactive Reference as before.
Line 8
let onClick = pipe (
read (count),
inc,
write (count)
)
Use pipe
to compose onClick
:
read (count)
: readcount
Reactive Referenceinc
: increase the valuewrite (count)
: writecount
Reactive Reference
Primitive
If we use console.log
for Reactive Reference of Primitive, we will get RefImpl
.
<script setup>
import { ref } from 'vue'
let count = ref (0)
let onClick = () => {
console.log ('count', count)
count.value++
}
</script>
<template>
<button @click="onClick">+</button> {{ count }}
</template>
Line 6
let onClick = () => {
console.log ('count', count)
count.value++
}
Use console.log
to show Reactive Reference.
Object
- If we use
console.log
for Reactive Reference of Object, we will getRefImpl
- If we use
.value
to unpack Reactive Reference of Object, we will getProxy
, not Plain Object. Sinceref
callsreactive
first to get Reactive Object and then pack into Reactive Reference
<script setup>
import { ref } from 'vue'
let store = ref ({ count: 0 })
let onClick = () => {
console.log ('store', store)
console.log ('store.value', store.value)
store.value.count++
}
</script>
<template>
<button @click="onClick">+</button> {{ store.count }}
</template>
Line 6
let onClick = () => {
console.log ('store', store)
console.log ('store.value', store.value)
store.value.count++
}
store.value
is Proxy, so we can use .count
to access count
.
Object Destructuring
Use Object Destructuring to Reactive Reference of Object and remain reactivity.
<script setup>
import { ref, toRefs } from 'vue'
let store = ref ({ count: 0 })
let onClick = () => {
console.log ('store', store)
console.log ('store.value', store.value)
let { count } = toRefs (store.value)
count.value++
}
</script>
<template>
<button @click="onClick">+</button> {{ store.count }}
</template>
Line 6
let onClick = () => {
console.log ('store', store)
console.log ('store.value', store.value)
let { count } = toRefs (store.value)
count.value++
}
- Since using
.value
to unpack Reactive Reference of Object is Proxy, we have to usetoRefs
first to convert it to Plain Object before destructuring - Destructured result is Reactive Reference. We have to use
.value
to access it
Conclusion
ref
in Vue 3 is great, but there are.value
everywhere in the codebase- We don’t have to concern about
.value
in Point-free style.read
andwrite
will handle.value
for us - If we see
RefImpl
in the console, it is a Reactive Reference. We have to use.value
to unpack it - If we use
ref
with Object, it will callreactive
first to make it a Reactive Object and then pack it as Reactive Reference. That’s why.value
of Reactive Reference of Object isProxy
- Since
.value
with Reactive Reference of Object is Proxy, we cannot use Object Destructuring to destructure Object. It will lose reactivity. We have to usetoRefs
first to convert it to a Plain Object before destructuring - Reactive Reference is good for Primitive, but Reactive Object is good for Object