Vue Composition APIで使えるリアクティブ関連のAPI一覧

Vue Composition APIのリファレンスを見たらリアクティブ周りのAPIが大量に追加されていたのでまとめてみました。

この記事は以下バージョン時点の情報です。

- [vuejs/composition-api](https://github.com/vuejs/composition-api): `v1.0.0-beta.1`
- [vuejs/vue-next](https://github.com/vuejs/vue-next): `v3.0.0-beta.17`

Vue Composition APIの[API Reference](https://vue-composition-api-rfc.netlify.app/api.html#setup) に掲載されているいくつかのAPIは、まだVue2系で使えるComposition APIのプラグイン（[vuejs/composition-api](https://github.com/vuejs/composition-api)）でサポートされていません。
そのAPIについては :warning: マークを末尾につけています。サポート対応状況については[こちらの記載](https://github.com/vuejs/composition-api#missing-apis)をもとにしています。


# [reactive](https://vue-composition-api-rfc.netlify.app/api.html#reactive)

引数に渡したオブジェクトのリアクティブなプロキシを返します。
Vue2系のVue.observable()と同等の機能です。ネストされたオブジェクトもリアクティブな値として保持されます。

```ts
const obj = reactive({
  name: "Foo",
  address: {
    city: "Bar"
  }
})

obj.address.city = "Huga"
console.log(obj.address.city) // Huga
```

型定義

```ts
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>;
```

# [ref](https://vue-composition-api-rfc.netlify.app/api.html#ref)

プリミティブな値をrefオブジェクトに変換して返します。refオブジェクトはvalueプロパティでリアクティブな値にアクセスできます。
refの値としてオブジェクトが代入されている場合は、reactiveメソッドによってオブジェクトを深くリアクティブにします。

```ts
const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1
```

型定義

```ts
interface Ref<T = any> {
    [RefSymbol]: true;
    value: T;
}

function ref<T extends object>(value: T): T extends Ref ? T : Ref<UnwrapRef<T>>;
function ref<T>(value: T): Ref<UnwrapRef<T>>;
function ref<T = any>(): Ref<T | undefined>;
```

# [computed](https://vue-composition-api-rfc.netlify.app/api.html#computed)

コールバック関数を受け取り、戻り値をリアクティブでReadonlyなrefオブジェクトとして返します。
refオブジェクトの値は、コールバック関数内にあるリアクティブな値の変化に応じて再計算されます。
（getterとsetterを持つオブジェクトを渡して書き込み可能なrefオブジェクトを作ることもできます）

```ts
const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2
count.value++
console.log(plusOne.value) // 3
plusOne.value = 4 // Error
```

型定義

```ts
// read-only
function computed<T>(getter: () => T): Readonly<Ref<Readonly<T>>>

// writable
function computed<T>(options: {
  get: () => T
  set: (value: T) => void
}): Ref<T>
```

# [readonly](https://vue-composition-api-rfc.netlify.app/api.html#readonly) ️:warning:

オブジェクト（ref or reactive or プレーン）を受け取り、読み取り専用のリアクティブなプロキシを返します。
軽量な独自storeの周りの実装で使えそうです。

※ 2020/07/03現在、vue-composition-apiプラグインではサポートされてません。

```ts
const original = reactive({ count: 0 })

const copy = readonly(original)
console.log(copy.count) // 0

original.count++
console.log(copy.count) // 1
console.log(isReactive(copy)) // true
copy.count++ // Error
```

型定義

```ts
function readonly<T extends object>(target: T): Readonly<UnwrapNestedRefs<T>>;
```


# [customRef](https://vue-composition-api-rfc.netlify.app/api.html#customref) :warning:
依存関係の追跡と更新のトリガーを明示的に制御するカスタマイズされたrefオブジェクトを返します。
限定された用途でリアクティブな値を使いたい時に良さそうです。

※ 2020/07/03現在、vue-composition-apiプラグインではサポートされてません。

```ts
// 代入と参照時に必ずconsole.log()を実行するref
const useLoggerRef = (value: string) => {
  return customRef((track, trigger) => ({
    get() {
      console.log(value)
      track()
      return value
    },
    set(newValue: string) {
      console.log(newValue)
      value = newValue
      trigger()
    }
  }))
}

const foo = useLoggerRef("")

foo.value = "Hoge" // console.log("Hoge")が実行される
foo.value = "Bar" // console.log("Bar")が実行される
const bar = foo.value // console.log("Bar")が実行される
```

型定義

```ts
function customRef<T>(factory: CustomRefFactory<T>): Ref<T>

type CustomRefFactory<T> = (
  track: () => void,
  trigger: () => void
) => {
  get: () => T
  set: (value: T) => void
}
```

# [markRaw](https://vue-composition-api-rfc.netlify.app/api.html#markraw)
リアクティブ化されない（プロキシされない）オブジェクトを返します。
適宜markRawを使いプロキシ変換をスキップすることで、不変のデータソースを持つ大規模なリストのレンダリングなどでパフォーマンスを向上させることができます。

```ts
const foo = markRaw({
  baz: "baz"
})
const bar = reactive(foo)
isReactive(bar) // false reactive関数を実行してもリアクティブにならない
```

型定義

```ts
function markRaw<T extends object>(value: T): T
```

# [shallowReactive](https://vue-composition-api-rfc.netlify.app/api.html#shallowreactive)
浅いリアクティブなオブジェクトを返します。ネストされたオブジェクトはリアクティブ化されません。

```ts
const state = shallowReactive({
  foo: 1,
  nested: {
    bar: 2
  }
})

isReactive(state) // true
isReactive(state.nested) // false
```

型定義

```ts
function shallowReactive<T extends object>(target: T): T;
```

# [shallowRef](https://vue-composition-api-rfc.netlify.app/api.html#shallowref)
浅いリアクティブなrefオブジェクトを返します。ネストされたオブジェクトはリアクティブ化されません。

```ts
const foo = ref({})
const bar = shallowRef({})

isReactive(foo.value) // true
isReactive(bar.value) // false
```

型定義

```ts
function shallowRef<T>(value: T): T extends Ref ? T : Ref<T>;
```

# [shallowReadonly](https://vue-composition-api-rfc.netlify.app/api.html#shallowreadonly) :warning:
浅いreadonlyなオブジェクトを返します。ネストされたオブジェクトはreadonlyになりません。

※ 2020/07/03現在、vue-composition-apiプラグインではサポートされてません。

```ts
const state = shallowReadonly({
  foo: 1,
  nested: {
    bar: 2
  }
})

// mutating state's own properties will fail
state.foo++
// ...but works on nested objects
isReadonly(state.nested) // false
state.nested.bar++ // works
```

型定義

```ts
function shallowReadonly<T extends object>(target: T): Readonly<{
    [K in keyof T]: UnwrapNestedRefs<T[K]>;
}>;
```

# [toRaw](https://vue-composition-api-rfc.netlify.app/api.html#toraw)
プロキシされたリアクティブなオブジェクトの生データを返します。

```ts
const foo = {}
const reactiveFoo = reactive(foo)

isReactive(toRaw(reactiveFoo)) // false
toRaw(reactiveFoo) === foo // true
```

型定義

```ts
function toRaw<T>(observed: T): T;
```

# [unref](https://vue-composition-api-rfc.netlify.app/api.html#unref)
引数がrefの場合は`ref.value`の値を、それ以外だったら引数自体を返します。
`val = isRef(val) ? val.value : val`  の糖衣構文です。

```ts
const foo = ref(1)
const bar = 1

unref(foo) // 1
unref(bar) // 1
```

型定義

```ts
function unref<T>(ref: T): T extends Ref<infer V> ? V : T;
```

# [toRef](https://vue-composition-api-rfc.netlify.app/api.html#toref)
reactiveなオブジェクトの指定のプロパティをrefオブジェクトに変換して返します。
propsの値をリアクティブを切らず、setup関数外のコンポーザブルな関数に渡すときなどに使えます。

```ts
const state = reactive({
  foo: 1,
  bar: 2
})

const fooRef = toRef(state, 'foo')
isRef(fooRef) // true
```

型定義

```ts
function toRef<T extends object, K extends keyof T>(object: T, key: K): Ref<T[K]>;
```

# [toRefs](https://vue-composition-api-rfc.netlify.app/api.html#torefs)
reactiveなオブジェクトの全てのプロパティをrefオブジェクトに変換したオブジェクトを返します。

```ts
const state = reactive({
  foo: 1,
  bar: 2
})

const stateAsRefs = toRefs(state)
isRef(stateAsRefs.foo) // true
isRef(stateAsRefs.bar) // true
```

型定義

```ts
type ToRefs<T = any> = {
    [K in keyof T]: Ref<T[K]>;
};
function toRefs<T extends object>(object: T): ToRefs<T>;
```

# [isRef](https://vue-composition-api-rfc.netlify.app/api.html#isref)
refオブジェクトでラップされているかどうかを判定します。

```ts
const foo = ref("foo");
const bar = reactive({
  bar: "bar"
});

isRef(foo) // true
isRef(bar) // false
```

型定義

```ts
isRef<T>(value: any): value is Ref<T>;
```

# [isReactive](https://vue-composition-api-rfc.netlify.app/api.html#isreactive)
reactiveかどうか判定します。reactiveで作られたオブジェクトをラップしたreadonlyなオブジェクトの場合にもtrueを返します。

```ts
const foo = ref("foo");
const bar = reactive({
  bar: "bar"
});
const baz = readonly(bar);
const hoge = readonly(foo)

isReactive(foo) // false
isReactive(bar) // true
isReactive(baz) // true
isReactive(hoge) // false
```

型定義

```ts
function isReactive(value: unknown): boolean;
```

# [isReadonly](https://vue-composition-api-rfc.netlify.app/api.html#isreadonly) :warning:
オブジェクトがreadonlyかどうか判定します。

※ 2020/07/03現在、vue-composition-apiプラグインではサポートされてません。

```ts
const foo = ref("foo");
const bar = reactive({
  bar: "bar"
});
const baz = readonly(bar);

isReadonly(foo) // false
isReadonly(bar) // false
isReadonly(baz) // true
```

型定義

```ts
function isReadonly(value: unknown): boolean;
```


# [isProxy](https://vue-composition-api-rfc.netlify.app/api.html#isproxy) :warning:
オブジェクトがProxyか判定します。reactiveかreadonlyで作成したオブジェクトが該当します。

※ 2020/07/03現在、vue-composition-apiプラグインではサポートされてません。

```ts
const foo = ref("foo");
const bar = reactive({
  bar: "bar"
});
const baz = readonly(bar);

isProxy(foo) // false
isProxy(bar) // true
isProxy(baz) // true
```

型定義

```ts
function isProxy(value: unknown): boolean;
```

# 終わりに
以上「Vue Composition API v1-beta で使えるリアクティブ関連のAPI一覧」でした。思った以上にAPIが多いですね。
業務ではref, reactive, toRef, toRefs, isRefくらいしか使ってなかったです。
今後はどんどん活用していきたいです。

# 参考

- https://composition-api.vuejs.org/api.html
- https://github.com/vuejs/composition-api