Back

Vue3のrefにObjectが代入されると、reactiveでwrapされるらしいのでコードを読む

Vue3のrefにObjectが代入されると、reactiveでwrapされるらしいのでコードを読む

こんにちは、合同会社Stegの@keigoです。 Vue3の ref()関数は、Objectが代入するとその値をreactive()でwrapするらしいです。

参考:https://ja.vuejs.org/api/reactivity-core.html#ref

本当にそうなの?というのが気になったので、コードを読んでみました。

コードを読んでいく

vuejs/coreのリポジトリの、reactive.tsのコードを読んでいきます。

記事執筆時点では、以下のようなコードになっています。

export const toReactive = <T extends unknown>(value: T): T =>
  isObject(value) ? reactive(value) : value

こちらは、toReactive関数の引数に来たvalueという変数がObjectである場合は、reactiveでwrapしています。

ではこのtoReactive関数は、ref関数が呼び出された時にどのように発火するのでしょうか。

1. ref関数の実装

ref関数の処理は、ref.tsに記述されています。 記事執筆時点では、以下のようなコードになっていました。

export function ref(value?: unknown) {
  return createRef(value, false)
}

createRef関数が呼び出されているのがわかります。

2. createRef関数の実装

createRef関数の実装は、以下のようになっていました。

function createRef(rawValue: unknown, shallow: boolean) {
  if (isRef(rawValue)) {
    return rawValue
  }
  return new RefImpl(rawValue, shallow)
}

RefImplクラスが呼び出されているのがわかります。

3. RefImplクラスの実装

RefImplクラスの実装は、以下のようになっていました。

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

  public dep?: Dep = undefined
  public readonly __v_isRef = true

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

コンストラクタにて、toReactiveが呼び出されています。

記述されている三項演算子は、以下のような条件になっています。

__v_isShallowという変数がtrueの場合はvalueが代入される。falseの場合はtoReactiveの返り値が代入される。

__v_isShallowという変数は、コンストラクタ実行次にreturn createRef(value, false)という呼び出し方をされているので、falseが代入されます。 したがって、toReactiveの関数が発火しています。

まとめ

Vue3のref関数にObjectを代入すると、reactive関数でwrapされることがわかりました。便利ですね。