點燈坊

失くすものさえない今が強くなるチャンスよ

Using ref to Create Reactive Reference

Sam Xiao's Avatar 2021-12-09

Reactivity is an essential part of Vue. We use ref to create a Reactive Reference of value.

Version

Vue 3.2

ref

ref000

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

ref000

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) : read count Reactive Reference
  • inc : increase the value
  • write (count) : write count Reactive Reference

Primitive

ref001

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

ref002

  • If we use console.log for Reactive Reference of Object, we will get RefImpl
  • If we use .value to unpack Reactive Reference of Object, we will get Proxy, not Plain Object. Since ref calls reactive 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

ref003

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 use toRefs 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 and write 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 call reactive first to make it a Reactive Object and then pack it as Reactive Reference. That’s why .value of Reactive Reference of Object is Proxy
  • Since .value with Reactive Reference of Object is Proxy, we cannot use Object Destructuring to destructure Object. It will lose reactivity. We have to use toRefs first to convert it to a Plain Object before destructuring
  • Reactive Reference is good for Primitive, but Reactive Object is good for Object