跳转到内容

toRef、toRefs、unRef、proxyRefs

刀刀
0字
0分钟
2026/8/17

Vue3 toRef

toRef 函数可以将一个响应式对象的属性转换为响应式引用,这样就可以在不直接修改原始对象的情况下,对对象的属性进行操作。

html
<body>
  <script type="module">
    import { ref, effect, reactive, toRef } from '../dist/reactivity.esm.js'

    const state = reactive({
      count: 0,
      name: 'John',
    })

    const countRef = toRef(state, 'count')
    console.log('countRef.value', countRef.value)

    effect(() => {
      console.log(state.count) // 1
    })

    setTimeout(() => {
      countRef.value = 1
    }, 1000)
  </script>
</body>

根据上面的示例代码,可以看出来,toRef 是一个函数,可以将一个响应式对象的属性转换为响应式引用,返回的是一个对象。

下面来实现一下。

ts
export function toRef(target, key) {
  return {
    get value() {
      return target[key]
    },
    set value(newValue) {
      target[key] = newValue
    },
  }
}
ts
class ObjectRefImpl {
  target
  key;
  [ReactiveFlags.IS_REF] = true
  constructor(target, key) {
    this.target = target
    this.key = key
  }

  get value() {
    return this.target[this.key]
  }

  set value(newValue) {
    this.target[this.key] = newValue
  }
}

export function toRef(target, key) {
  return new ObjectRefImpl(target, key)
}

Vue3 toRefs

toRefs 函数可以将一个响应式对象的多个属性转换为响应式。

html
<body>
  <script type="module">
    import {
      ref,
      effect,
      reactive,
      toRef,
      toRefs,
    } from '../dist/reactivity.esm.js'

    const state = reactive({
      count: 0,
      name: 'John',
    })

    const { count, name } = toRefs(state)

    effect(() => {
      console.log(state) // 1
    })

    setTimeout(() => {
      count.value = 1
      name.value = 'Jane'
    }, 1000)
  </script>
</body>

前面已经写过 toRef 了,这里实现 toRefs 功能就更简单了,只需要遍历对象的属性,将每个属性转换为响应式引用即可。

ref.ts
ts
export function toRefs(target) {
  const res = {}

  for (const key in target) {
    res[key] = toRef(target, key)
  }

  return res
}

Vue3 unRef

unRef 函数可以将一个响应式引用转换为普通值。

ref.ts
ts
// 如果这个 target 是 ref,返回 target.value,否则返回 target
export function unRef(target) {
  return isRef(target) ? target.value : target
}

Vue3 proxyRefs

proxyRefs 主要用于简化 ref.value 操作,使代码更简洁。

ref.ts
ts
export function proxyRefs(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      /**
       * 自动解包 ref
       */
      const res = target[key]
      return unRef(res)
    },
    set(target, key, newValue, receiver) {
      const oldValue = target[key]
      /**
       * 浅层的 ref 操作
       */
      if (isRef(target[key]) && !isRef(newValue)) {
        oldValue.value = newValue
        return true
      }

      return Reflect.set(target, key, newValue, receiver)
    },
  })
}

贡献者

The avatar of contributor named as duyidao duyidao
The avatar of contributor named as 刀刀 刀刀

页面历史

刀刀博客累计访客 人;文档累计访问量共