Create Adaptable Composable
Adaptable composables are reusable functions that can accept both reactive and non-reactive inputs. This allows developers to use the composable in a variety of contexts without worrying about the reactivity of the inputs.
Steps to design an adaptable composable in Vue.js:
- •Confirm the composable's purpose and API design and expected inputs/outputs.
- •Identify inputs params that should be reactive (MaybeRef / MaybeRefOrGetter).
- •Use
toValue()ortoRef()to normalize inputs inside reactive effects. - •Implement the core logic of the composable using Vue's reactivity APIs.
Core Type Concepts
Type Utilities
ts
/** * value or writable ref (value/ref/shallowRef/writable computed) */ export type MaybeRef<T = any> = T | Ref<T> | ShallowRef<T> | WritableComputedRef<T> /** * MaybeRef<T> + ComputedRef<T> + () => T */ export type MaybeRefOrGetter<T = any> = MaybeRef<T> | ComputedRef<T> | (() => T)
Policy and Rules
- •Read-only, computed-friendly input: use
MaybeRefOrGetter - •Needs to be writable / two-way input: use
MaybeRef - •Parameter might be a function value (callback/predicate/comparator): do not use
MaybeRefOrGetter, or you may accidentally invoke it as a getter. - •DOM/Element targets: if you want computed/derived targets, use
MaybeRefOrGetter.
When MaybeRefOrGetter or MaybeRef is used:
- •resolve reactive value using
toRef()(e.g. watcher source) - •resolve non-reactive value using
toValue()
Examples
Adaptable useDocumentTitle Composable: read-only title parameter
ts
import { watch, toRef } from 'vue'
import type { MaybeRefOrGetter } from 'vue'
export function useDocumentTitle(title: MaybeRefOrGetter<string>) {
watch(
toRef(title),
(t) => {
document.title = t
},
{ immediate: true }
)
}
Adaptable useCounter Composable: two-way writable count parameter
ts
import { watch, toRef } from 'vue'
import type { MaybeRef } from 'vue'
function useCounter(count: MaybeRef<number>) {
const countRef = toRef(count)
function add() {
countRef.value++
}
return { add }
}