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されることがわかりました。便利ですね。