More articles

preface

Reactive was introduced in the previous article, and this article introduces the REF-related apis

Simplify the code

Vue3-ref source location

class

Reactive is a Proxy, and ref is a class reactive

ref

Source code implementation:

export function ref(value? : unknown) {
  return createRef(value, false)}function createRef(rawValue: unknown, shallow: boolean) {
  if (isRef(rawValue)) {
    return rawValue
  }
  return new RefImpl(rawValue, shallow)
}
Copy the code

Vue returns a RefImpl via createRef. RefImpl is a class

class RefImpl<T> {
  private _value: T
  private _rawValue: T

  publicdep? : Dep =undefined
  public readonly __v_isRef = true

  constructor(value: T, public readonly _shallow: boolean) {
    this._rawValue = _shallow ? value : toRaw(value)
    this._value = _shallow ? value : convert(value)
  }

  get value() {
    trackRefValue(this)
    return this._value
  }

  set value(newVal) {
    newVal = this._shallow ? newVal : toRaw(newVal)
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal
      this._value = this._shallow ? newVal : convert(newVal)
      triggerRefValue(this, newVal)
    }
  }
}
Copy the code

Get returns this._value. By default, convert is used to retrieve real data

const convert = <T extends unknown>(val: T): T => isObject(val) ? reactive(val) : val
Copy the code

RefImpl: RefImpl: RefImpl: RefImpl: RefImpl: RefImpl: RefImpl: RefImpl: RefImpl: RefImpl: RefImpl: RefImpl: RefImpl: RefImpl

// If the object is reactive
const convert = val= > isObject(val) ? reactive(val) : val

class RefImpl {
  constructor(value, shallow) {
    this.__v_isRef = true
    this._rawValue = shallow ? value : toRaw(value)
    this._value = shallow ? value : convert(value)
    this._shallow = shallow
  }

  get value() {
    return this._value
  }

  set value(newValue) {
    newValue = this._shallow ? newValue : toRaw(newValue)
    if(hasChanged(newValue, this._rawValue)) {
      this._rawValue = newValue;
      this._value = this._shallow ? newValue : convert(newValue)
    }
  }
}

function createRef(value, shallow) {
  if(isRef(value)) return value
  return new RefImpl(value, shallow);
}

function ref(value) {
  return createRef(value, false)}Copy the code

isRef

RefImpl has a read-only __v_isRef attribute, which is used to determine whether it is ref

function isRef(r) {
  return r && r.__v_isRef === true
}
Copy the code

unref

If the parameter is a ref, the internal value is returned, otherwise the parameter itself is returned

function unref(ref) {
  return isRef(ref) ? ref.value : ref
}
Copy the code

toRef

The toRef implementation also manipulates the source object by manipulating the value attribute through the set and GET methods of the custom class

class ObjectRefImpl {
  constructor(_object, _key) {
    this.__v_isRef = true
    this._object = _object
    this._key = _key
  }
  get value() {
    // Get reactive
    return this._object[this._key]
  }
  set value(newVal) {
    // Set reactive
    this._object[this._key] = newVal
  }
}
function toRef(target, key) {
  const value = target[key]
  return isRef(value) ? value : new ObjectRefImpl(target, key)
}
Copy the code

toRefs

ToRefs is an operation on a reactive object with the help of a toRef

function toRefs(object) {
  if(! isProxy(object)) {console.warn(`toRefs() expects a reactive object but received a plain one.`)}const ret = isArray(object) ? new Array(object.length) : {}
  for (const key in object) {
    ret[key] = toRef(object, key)
  }
  return ret
}
Copy the code

shallowRef

ShallowRef will follow the change of ref, but will not make. Value reactive. Shallow is set to true, and ref will not go convert if it is an object

function shallowRef(value) {
  return createRef(value, true)}Copy the code

customRef

CustomRef receives a factory function that returns custom GET and set methods. The custom GET and SET methods are called when fetching and assigning values, respectively. There is no data collection involved here, just a simple logical implementation

class CustomRefImpl {
  constructor(factory) {
    const { get, set } = factory()
    this._get = get
    this._set = set
  }

  get value() {
    return this._get()
  }
  
  set value(newValue) {
    this._set(newValue)
  }
}
function customRef(factory) {
  return new CustomRefImpl(factory)
}
Copy the code

conclusion

This look at the source code to write unexpected harvest