Skip to content

ref

官方文档建议在ref中放入原始数据类型进行操作.

在实际开发中, 其实也可以放入对象和数组, 比如:

vue
<script setup>
import { ref } from 'vue'

const users = ref(['zhangsan', 'lisi'])

console.log(users.value)
</script>

主要原因是如果在开发过程中存在大量的refreactive 和 普通js对象并行, 就会加重"我现在操作的是否是ref对象"的心智负担.

统一使用ref操作可以降低这种心智负担.(虽然我不喜欢.value的操作)

优点:

  1. 显示调用, 有明确的类型检查.
  2. 相比reactive的局限更少

如何解决呢?

在使用watch直接接受ref作为监听对象, 并在回调函数中返回解包后的值

vue
<script setup>
const counter = ref(0)

watch(counter, count => {
  // 这时的 count 已经解包, 不再需要 `.value`
  console.log(count) 
})
</script>

以及可以在模板中自动解包

vue
<template>
  <button @click="counter += 1">Counter is {{ counter }}</button>
</template>

甚至可以用reactive再包一层:

vue
<script setup>
const name = ref('zhangsan')

const user = reactive({
  name,
  age: 18
})

// 这时可以操作 user.name, 不在需要 user.name.value
user.name // zhangsan
</script>

unref

这个在业务组件用到的不太多, 功能性组件更多一点. 因为可以在接收到一个未知类型的数据时候, 直接unref(whatEverThisIs)

大概的实现就是

typescript
function unref<T>(r: Ref<T> | T): T {
  return isRef(r) ? r.value : r
}

实际使用的时候就无脑unref

typescript
import { ref, unref } from 'vue'

function myTool(whatEverThisIs: any) {
  return unref(whatEverThisIs)
}

使用MaybeRef类型简化开发

typescript
type MaybeRef<T> = T | Ref<T>

export function useTimeAgo(
  time: MaybeRef<Date | number | string>,
) {
  return computed(() => someFormatting(unref(time)))
}

ref 绑定一个已有的 ref

typescript
import { ref, computed } from 'vue'
import { useTitle } from '@vueuse/core'

const name = ref('Hello')
const title = computed(() => {
  return `${name.value} my friend`
})

// 这时绑定
useTitle(title) // Hello my friend

name.value = `hi` // hi my friend

如果重复使用已有的ref会发生什么呢?

它会原样返回

vue
<script setup>
import { ref, reactive } from 'vue'

const name = ref('zhangsan')
// 这时 如果使用下面的操作, 会发生什么呢?
const anotherName = ref(name)

name === anotherName // true

</script>

使用由 refreactive 组成的对象

vue
<script setup>
import { ref, reactive } from 'vue'

function useMouse() {
  return {
      x: ref(0),
      y: ref(0)
    }
}
// 可以单独使用 x 或 y
const { x, y } = useMouse()
// 也可以使用 reactive

const mouse = reactive(useMouse())

// 这时这两种都可以使用, 也可以保留响应式
// 防止ES6 解构造成的响应式丢失
mouse.x === x.value
</script>

接收ref 作为函数参数

通常实现的函数:

typescript
function add(a: number, b: number) {
  return a + b
}

结果不会触发响应式更新

Vue 中可以接收 ref 类型, 返回一个响应式结果

typescript
function add(a: Ref<number>, b: Ref<number>) {
  return computed(() => a.value + b.value)
}

ab 的数值发生变化时, 会自动触发响应式更新

javascript
const a = ref(1)
const b = ref(2)

let c = add(a, b)

这时的 c 已经不在单纯的是一个固定的值, 而是一个响应式的表达式了

Made with ❤️ by Xin