07-to系列全家桶

Huxzhi大约 2 分钟vue3

toRef

应用场景 比如你请求拿到一个对象,但是只用其中某个属性,并且是响应式 把属性解构出来

toref 只能修改响应式对象的值 非常响应式视图毫无变化

<template>
   <div>
      <button @click="change">按钮</button>
      {{state}}
   </div>
</template>

<script setup lang="ts">
import { reactive, toRef } from 'vue'

const obj = {
   foo: 1,
   bar: 1
}


const state = toRef(obj, 'bar')
// bar 转化为响应式对象

const change = () => {
   state.value++
   console.log(obj, state);

}
</script>

如果原始对象是响应式的是会更新视图并且改变数据的 原因:toRef 源码解析

toRefs

可以帮我们批量创建 ref 对象主要是方便我们解构使用

import { reactive, toRefs } from 'vue'
const obj = reactive({
   foo: 1,
   bar: 1
})

let { foo, bar } = toRefs(obj)

foo.value++
console.log(foo, bar);

toRaw

将响应式对象转化为普通对象

当你使用响应式获取到了 input 的值,并用来 get,post 时就要原生对象

import { reactive, toRaw } from 'vue'

const obj = reactive({
   foo: 1,
   bar: 1
})


const state = toRaw(obj)
// 响应式对象转化为普通对象

const change = () => {

   console.log(obj, state);

}

toRef 源码解析

如果是 ref 对象直接返回 否则 调用   ObjectRefImpl 创建一个类 ref 对象

没有做收集依赖和触发更新

export function toRef<T extends object, K extends keyof T>(
  object: T,
  key: K,
  defaultValue?: T[K]
): ToRef<T[K]> {
  const val = object[key]
  return isRef(val)
    ? val
    : (new ObjectRefImpl(object, key, defaultValue) as any)
}

类 ref 对象只是做了值的改变 并未处理 收集依赖触发依赖的过程 所以 普通对象无法更新视图

ref 响应式对象 更新视图是因为调用了 reactive ^ref

class ObjectRefImpl<T extends object, K extends keyof T> {
  public readonly __v_isRef = true

  constructor(
    private readonly _object: T,
    private readonly _key: K,
    private readonly _defaultValue?: T[K]
  ) {}

  get value() {
    const val = this._object[this._key]
    return val === undefined ? (this._defaultValue as T[K]) : val
  }

  set value(newVal) {
    this._object[this._key] = newVal
  }
}

toRefs 源码解析

其实就是把 reactive 对象的每一个属性都变成了 ref 对象循环 调用了 toRef

export type ToRefs<T = any> = {
  [K in keyof T]: ToRef<T[K]>
}
export function toRefs<T extends object>(object: T): ToRefs<T> {
  if (__DEV__ && !isProxy(object)) {
    console.warn(`toRefs() expects a reactive object but received a plain one.`)
  }
  const ret: any = isArray(object) ? new Array(object.length) : {}
  for (const key in object) {
    ret[key] = toRef(object, key)
  }
  return ret
}

toRaw 源码解析

通过   ReactiveFlags 枚举值 取出 proxy 对象的 原始对象

一句话就是,取出objobj['__v_raw'] 的值

export const enum ReactiveFlags {
  SKIP = '__v_skip',
  IS_REACTIVE = '__v_isReactive',
  IS_READONLY = '__v_isReadonly',
  IS_SHALLOW = '__v_isShallow',
  RAW = '__v_raw'
}

export function toRaw<T>(observed: T): T {
  const raw = observed && (observed as Target)[ReactiveFlags.RAW]
  return raw ? toRaw(raw) : observed
}