From 8a4c9610260e36a0120860eddd430ef51a5d7ce0 Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Fri, 22 Oct 2021 13:04:47 +0200 Subject: [PATCH 01/18] Add inline doc for computed, reactive and ref functions Relates to #4832 I basically copied over most of the documentation text and examples from the docs pages (and potentially merged it with already-existing inline docs). --- packages/reactivity/src/computed.ts | 29 ++++ packages/reactivity/src/reactive.ts | 246 ++++++++++++++++++++++++-- packages/reactivity/src/ref.ts | 256 ++++++++++++++++++++++++++++ 3 files changed, 514 insertions(+), 17 deletions(-) diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index e9f36ecd22f..4987bdca91f 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -68,10 +68,39 @@ export class ComputedRefImpl { } } +/** + * Takes a getter function and returns an immutable reactive ref object for the + * returned value from the getter. + * + * ```js + * const count = ref(1) + * const plusOne = computed(() => count.value + 1) + * + * console.log(plusOne.value) // 2 + * + * plusOne.value++ // error + * ``` + */ export function computed( getter: ComputedGetter, debugOptions?: DebuggerOptions ): ComputedRef +/** + * Takes an object with get and set functions to create a writable ref object. + * + * ```js + * const count = ref(1) + * const plusOne = computed({ + * get: () => count.value + 1, + * set: val => { + * count.value = val - 1 + * } + *}) + * + * plusOne.value = 1 + * console.log(count.value) // 0 + * ``` + */ export function computed( options: WritableComputedOptions, debugOptions?: DebuggerOptions diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index 83e1c7abee1..7953a8f1e63 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -67,23 +67,43 @@ export type UnwrapNestedRefs = T extends Ref ? T : UnwrapRefSimple /** * Creates a reactive copy of the original object. * - * The reactive conversion is "deep"β€”it affects all nested properties. In the + * The reactive conversion is "deep" β€” it affects all nested properties. In the * ES2015 Proxy based implementation, the returned proxy is **not** equal to the * original object. It is recommended to work exclusively with the reactive * proxy and avoid relying on the original object. * - * A reactive object also automatically unwraps refs contained in it, so you - * don't need to use `.value` when accessing and mutating their value: + * **Note:** `reactive` will unwrap all the deep refs, while maintaining the ref + * reactivity: * * ```js - * const count = ref(0) - * const obj = reactive({ - * count - * }) + * const count = ref(1) + * const obj = reactive({ count }) + * + * // ref will be unwrapped + * console.log(obj.count === count.value) // true + * + * // it will update `obj.count` + * count.value++ + * console.log(count.value) // 2 + * console.log(obj.count) // 2 * + * // it will also update `count` ref * obj.count++ - * obj.count // -> 1 - * count.value // -> 1 + * console.log(obj.count) // 3 + * console.log(count.value) // 3 + * ``` + * + * **Important:** When assigning a ref to a reactive property, that ref will be + * automatically unwrapped: + * + * ```js + * const count = ref(1) + * const obj = reactive({}) + * + * obj.count = count + * + * console.log(obj.count) // 1 + * console.log(obj.count === count.value) // true * ``` */ export function reactive(target: T): UnwrapNestedRefs @@ -106,9 +126,28 @@ export declare const ShallowReactiveMarker: unique symbol export type ShallowReactive = T & { [ShallowReactiveMarker]?: true } /** - * Return a shallowly-reactive copy of the original object, where only the root - * level properties are reactive. It also does not auto-unwrap refs (even at the - * root level). + * Returns a shallowly-reactive copy of the original object. + * + * This proxy will track reactivity of its own properties but does not perform + * deep reactive conversion of nested objects (i.e. it exposes "raw" values). + * + * Unlike `reactive`, any property that uses a ref will **not** be automatically + * unwrapped by the proxy (even at the root level). + * + * ```js + * const state = shallowReactive({ + * foo: 1, + * nested: { + * bar: 2 + * } + * }) + * + * // mutating state's own properties is reactive + * state.foo++ + * // ...but does not convert nested objects + * isReactive(state.nested) // false + * state.nested.bar++ // non-reactive + * ``` */ export function shallowReactive( target: T @@ -147,8 +186,45 @@ export type DeepReadonly = T extends Builtin : Readonly /** - * Creates a readonly copy of the original object. Note the returned copy is not - * made reactive, but `readonly` can be called on an already reactive object. + * Creates a readonly copy of the original object. + * + * Takes an object (reactive or plain) or a ref and returns a readonly proxy to + * the original. A readonly proxy is "deep": any nested property accessed will + * be readonly as well. + * + * ```js + * const original = reactive({ count: 0 }) + * + * const copy = readonly(original) + * + * watchEffect(() => { + * // works for reactivity tracking + * console.log(copy.count) + * }) + * + * // mutating original will trigger watchers relying on the copy + * original.count++ + * + * // mutating the copy will fail and result in a warning + * copy.count++ // warning! + * ``` + * + * As with `reactive`, if any property uses a ref it will be automatically + * unwrapped when it is accessed via the proxy: + * + * ```js + * const raw = { + * count: ref(123) + *} + * + * const copy = readonly(raw) + * + * console.log(raw.count.value) // 123 + * console.log(copy.count) // 123 + * ``` + * + * Note: The returned copy is not made reactive, but `readonly` can be called on + * an already reactive object. */ export function readonly( target: T @@ -163,9 +239,29 @@ export function readonly( } /** - * Returns a reactive-copy of the original object, where only the root level - * properties are readonly, and does NOT unwrap refs nor recursively convert - * returned properties. + * Returns a shallowly-reactive copy of the original object. + * + * Creates a proxy that makes its own properties readonly, but does not perform + * deep readonly conversion of nested objects (exposes raw values). + * + * ```js + * 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 + * ``` + * + * Unlike `readonly`, any property that uses a ref will **not** be automatically + * unwrapped by the proxy. + * * This is used for creating the props proxy object for stateful components. */ export function shallowReadonly(target: T): Readonly { @@ -217,6 +313,44 @@ function createReactiveObject( return proxy } +/** + * Checks if an object is a reactive proxy created by `reactive`. + * + * ```js + * import { reactive, isReactive } from 'vue' + * export default { + * setup() { + * const state = reactive({ + * name: 'John' + * }) + * console.log(isReactive(state)) // -> true + * } + * } + * ``` + * + * It also returns `true` if the proxy is created by `readonly`, but is + * wrapping another proxy created by `reactive`. + * + * ```js + * import { reactive, isReactive, readonly } from 'vue' + * export default { + * setup() { + * const state = reactive({ + * name: 'John' + * }) + * // readonly proxy created from plain object + * const plain = readonly({ + * name: 'Mary' + * }) + * console.log(isReactive(plain)) // -> false + * + * // readonly proxy created from reactive proxy + * const stateCopy = readonly(state) + * console.log(isReactive(stateCopy)) // -> true + * } + * } + * ``` + */ export function isReactive(value: unknown): boolean { if (isReadonly(value)) { return isReactive((value as Target)[ReactiveFlags.RAW]) @@ -224,6 +358,9 @@ export function isReactive(value: unknown): boolean { return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE]) } +/** + * Checks if an object is a readonly proxy created by `readonly`. + */ export function isReadonly(value: unknown): boolean { return !!(value && (value as Target)[ReactiveFlags.IS_READONLY]) } @@ -232,10 +369,28 @@ export function isShallow(value: unknown): boolean { return !!(value && (value as Target)[ReactiveFlags.IS_SHALLOW]) } +/** + * Checks if an object is a proxy created by `reactive` or `readonly`. + */ export function isProxy(value: unknown): boolean { return isReactive(value) || isReadonly(value) } +/** + * Returns the raw, original object of a reactive or readonly proxy. + * + * This is an escape hatch that can be used to temporarily read without + * incurring proxy access/tracking overhead or write without triggering changes. + * It is **not** recommended to hold a persistent reference to the original + * object. Use with caution. + * + * ```js + * const foo = {} + * const reactiveFoo = reactive(foo) + * + * console.log(toRaw(reactiveFoo) === foo) // true + * ``` + */ export function toRaw(observed: T): T { const raw = observed && (observed as Target)[ReactiveFlags.RAW] return raw ? toRaw(raw) : observed @@ -243,13 +398,70 @@ export function toRaw(observed: T): T { export type Raw = T & { [RawSymbol]?: true } +/** + * Marks an object so that it will never be converted to a proxy. + * + * Returns the object itself. + * + * ```js + * const foo = markRaw({}) + * console.log(isReactive(reactive(foo))) // false + * + * // also works when nested inside other reactive objects + * const bar = reactive({ foo }) + * console.log(isReactive(bar.foo)) // false + * ``` + * + * **Warning:** `markRaw` and the `shallowXXX` APIs below allow you to + * selectively opt-out of the default deep reactive/readonly conversion and + * embed raw, non-proxied objects in your state graph. They can be used for + * various reasons: + * + * * Some values simply should not be made reactive, for example a complex 3rd + * party class instance, or a Vue component object. + * * Skipping proxy conversion can provide performance improvements when + * rendering large lists with immutable data sources. + * + * They are considered advanced because the raw opt-out is only at the root + * level, so if you set a nested, non-marked raw object into a reactive object + * and then access it again, you get the proxied version back. This can lead to + * **identity hazards** - i.e. performing an operation that relies on object + * identity but using both the raw and the proxied version of the same object: + * + * ```js + * const foo = markRaw({ + * nested: {} + * }) + * + * const bar = reactive({ + * // although `foo` is marked as raw, foo.nested is not. + * nested: foo.nested + * }) + * + * console.log(foo.nested === bar.nested) // false + * ``` + * + * Identity hazards are in general rare. However, to properly utilize these APIs + * while safely avoiding identity hazards requires a solid understanding of how + * the reactivity system works. + */ export function markRaw(value: T): Raw { def(value, ReactiveFlags.SKIP, true) return value } +/** + * Returns a reactive proxy of the given value (if possible). + * + * If the given value is not an object, the original value itself is returned. + */ export const toReactive = (value: T): T => isObject(value) ? reactive(value) : value +/** + * Returns a readonly proxy of the given value (if possible). + * + * If the given value is not an object, the original value itself is returned. + */ export const toReadonly = (value: T): T => isObject(value) ? readonly(value as Record) : value diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 9bb4ce29be5..45eab6d14c0 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -69,15 +69,60 @@ export function triggerRefValue(ref: RefBase, newVal?: any) { } } +/** + * Checks if a value is a ref object. + */ export function isRef(r: Ref | unknown): r is Ref export function isRef(r: any): r is Ref { return !!(r && r.__v_isRef === true) } +/** + * Takes an object as inner value and returns a reactive and mutable ref object. + * + * The ref object has a single `value` property that points to the inner value. + * The object is made deeply reactive by the `reactive` function. + * + * If the type of the generic is unknown, it's recommended to cast ref to + * `Ref`: + * + * ```ts + * function useState(initial: State) { + * const state = ref(initial) as Ref // state.value -> State extends string + * return state + * } + * ``` + */ export function ref( value: T ): [T] extends [Ref] ? T : Ref> +/** + * Takes an inner value and returns a reactive and mutable ref object. + * + * The ref object has a single `value` property that points to the inner value. + * + * ```js + * const count = ref(0) + * console.log(count.value) // 0 + * count.value++ + * console.log(count.value) // 1 + * ``` + * + * Sometimes we may need to specify complex types for a ref's inner value. We + * can do that succinctly by passing a generics argument when calling `ref` to + * override the default inference: + * + * ```ts + * const foo = ref('foo') // foo's type: Ref + * foo.value = 123 // ok! + * ``` + */ export function ref(value: T): Ref> +/** + * Takes an inner value and returns a reactive and mutable ref object. + * + * The ref has a single `value` property that points to the inner value. + */ export function ref(): Ref export function ref(value?: unknown) { return createRef(value, false) @@ -87,10 +132,52 @@ declare const ShallowRefMarker: unique symbol export type ShallowRef = Ref & { [ShallowRefMarker]?: true } +/** + * Creates a ref that tracks mutations on its own `value` but doesn't make its + * value reactive. + * + * ```js + * const foo = shallowRef({}) + * // mutating the ref's value is reactive + * foo.value = {} + * // but the value will not be converted. + * isReactive(foo.value) // false + * ``` + * + * See also: https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs + */ export function shallowRef( value: T ): T extends Ref ? T : ShallowRef +/** + * Creates a ref that tracks mutations on its own `value` but doesn't make its + * value reactive. + * + * ```js + * const foo = shallowRef({}) + * // mutating the ref's value is reactive + * foo.value = {} + * // but the value will not be converted. + * isReactive(foo.value) // false + * ``` + * + * See also: https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs + */ export function shallowRef(value: T): ShallowRef +/** + * Creates a ref that tracks mutations on its own `value` but doesn't make its + * value reactive. + * + * ```js + * const foo = shallowRef({}) + * // mutating the ref's value is reactive + * foo.value = {} + * // but the value will not be converted. + * isReactive(foo.value) // false + * ``` + * + * See also: https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs + */ export function shallowRef(): ShallowRef export function shallowRef(value?: unknown) { return createRef(value, true) @@ -132,10 +219,44 @@ class RefImpl { } } +/** + * Execute any effects tied to a shallow ref manually. + * + * ```js + * const shallow = shallowRef({ + * greet: 'Hello, world' + * }) + * + * // Logs "Hello, world" once for the first run-through + * watchEffect(() => { + * console.log(shallow.value.greet) + * }) + * + * // This won't trigger the effect because the ref is shallow + * shallow.value.greet = 'Hello, universe' + * + * // Logs "Hello, universe" + * triggerRef(shallow) + * ``` + * + * See also: https://v3.vuejs.org/api/computed-watch-api.html#watcheffect + */ export function triggerRef(ref: Ref) { triggerRefValue(ref, __DEV__ ? ref.value : void 0) } +/** + * Returns the inner value if the argument is a ref, otherwise return the + * argument itself. + * + * This is a sugar function for `val = isRef(val) ? val.value : val`. + * + * ```js + * function useFoo(x: number | Ref) { + * const unwrapped = unref(x) // unwrapped is guaranteed to be number now + * } + * ``` + */ export function unref(ref: T | Ref): T { return isRef(ref) ? (ref.value as any) : ref } @@ -153,6 +274,9 @@ const shallowUnwrapHandlers: ProxyHandler = { } } +/** + * todo: document? This is published in vue-core, as well! + */ export function proxyRefs( objectWithRefs: T ): ShallowUnwrapRef { @@ -195,6 +319,46 @@ class CustomRefImpl { } } +/** + * Creates a customized ref with explicit control over its dependency tracking + * and updates triggering. + * + * It expects a factory function, which receives `track` and `trigger` functions + * as arguments and should return an object with `get` and `set`. + * + * Example using a custom ref to implement debounce with `v-model`: + * + * ```js + * // in the template: + * + * function useDebouncedRef(value, delay = 200) { + * let timeout + * return customRef((track, trigger) => { + * return { + * get() { + * track() + * return value + * }, + * set(newValue) { + * clearTimeout(timeout) + * timeout = setTimeout(() => { + * value = newValue + * trigger() + * }, delay) + * } + * } + * }) + * } + * + * export default { + * setup() { + * return { + * text: useDebouncedRef('hello') + * } + * } + * } + * ``` + */ export function customRef(factory: CustomRefFactory): Ref { return new CustomRefImpl(factory) as any } @@ -202,6 +366,62 @@ export function customRef(factory: CustomRefFactory): Ref { export type ToRefs = { [K in keyof T]: ToRef } + +/** + * Converts a reactive object to a plain object where each property of the + * resulting object is a ref pointing to the corresponding property of the + * original object. + * + * ```js + * const state = reactive({ + * foo: 1, + * bar: 2 + * }) + * + * // type of stateAsRefs: { foo: Ref, bar: Ref } + * const stateAsRefs = toRefs(state) + * + * // The ref and the original property is "linked" + * state.foo++ + * console.log(stateAsRefs.foo.value) // 2 + * + * stateAsRefs.foo.value++ + * console.log(state.foo) // 3 + * ``` + * + * `toRefs` is useful when returning a reactive object from a composition + * function so that the consuming component can destructure/spread the returned + * object without losing reactivity: + * + * ```js + * function useFeatureX() { + * const state = reactive({ + * foo: 1, + * bar: 2 + * }) + * + * // logic operating on state + * + * // convert to refs when returning + * return toRefs(state) + * } + * + * export default { + * setup() { + * // can destructure without losing reactivity + * const { foo, bar } = useFeatureX() + * + * return { + * foo, + * bar + * } + * } + * } + * ``` + * + * `toRefs` will only generate refs for properties that are included in the + * source object. To create a ref for a specific property use `toRef` instead. + */ export function toRefs(object: T): ToRefs { if (__DEV__ && !isProxy(object)) { console.warn(`toRefs() expects a reactive object but received a plain one.`) @@ -238,6 +458,42 @@ class ObjectRefImpl { export type ToRef = IfAny, [T] extends [Ref] ? T : Ref> +/** + * Can be used to create a ref for a property on a source reactive object. + * + * The ref can then be passed around, retaining the reactive connection to its + * source property. + * + * ```js + * const state = reactive({ + * foo: 1, + * bar: 2 + * }) + * + * const fooRef = toRef(state, 'foo') + * + * fooRef.value++ + * console.log(state.foo) // 2 + * + * state.foo++ + * console.log(fooRef.value) // 3 + * ``` + * + * `toRef` is useful when you want to pass the ref of a prop to a composition + * function: + * + * ```js + * export default { + * setup(props) { + * useSomeFeature(toRef(props, 'foo')) + * } + * } + * ``` + * + * `toRef` will return a usable ref even if the source property doesn't + * currently exist. This makes it especially useful when working with optional + * props, which wouldn't be picked up by `toRefs`. + */ export function toRef( object: T, key: K From 8e51437d7bde1cf64f606bab5ad107b8b40f627d Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Fri, 22 Oct 2021 23:47:27 +0200 Subject: [PATCH 02/18] Shorten inline docs a bit --- packages/reactivity/src/computed.ts | 28 +++-- packages/reactivity/src/reactive.ts | 185 ++++++++-------------------- packages/reactivity/src/ref.ts | 141 ++++++--------------- 3 files changed, 111 insertions(+), 243 deletions(-) diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index 4987bdca91f..277f161f979 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -69,37 +69,47 @@ export class ComputedRefImpl { } /** - * Takes a getter function and returns an immutable reactive ref object for the - * returned value from the getter. + * Creates an immutable reactive ref object. * + * The `getter` function's return value determines the ref's value. + * + * @example * ```js * const count = ref(1) * const plusOne = computed(() => count.value + 1) * * console.log(plusOne.value) // 2 - * * plusOne.value++ // error * ``` + * + * @param getter Function that produces the next value. + * @param debugOptions */ export function computed( getter: ComputedGetter, debugOptions?: DebuggerOptions ): ComputedRef /** - * Takes an object with get and set functions to create a writable ref object. + * Creates a writable ref object. * + * The given object with `get` and `set` functions define the ref's behavior. + * + * @example * ```js * const count = ref(1) * const plusOne = computed({ - * get: () => count.value + 1, - * set: val => { - * count.value = val - 1 - * } - *}) + * get: () => count.value + 1, + * set: val => { + * count.value = val - 1 + * } + * }) * * plusOne.value = 1 * console.log(count.value) // 0 * ``` + * + * @param options Object holding the `get` and `set` functions. + * @param debugOptions */ export function computed( options: WritableComputedOptions, diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index 7953a8f1e63..965d5ee638c 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -65,46 +65,33 @@ function getTargetType(value: Target) { export type UnwrapNestedRefs = T extends Ref ? T : UnwrapRefSimple /** - * Creates a reactive copy of the original object. + * Creates a deeply-reactive copy of the original object. * - * The reactive conversion is "deep" β€” it affects all nested properties. In the - * ES2015 Proxy based implementation, the returned proxy is **not** equal to the - * original object. It is recommended to work exclusively with the reactive - * proxy and avoid relying on the original object. + * All (deep) refs within the object will be unwrapped, while maintaining the + * ref's reactivity. This is also done for refs that are assigned after creation + * of the proxy object. * - * **Note:** `reactive` will unwrap all the deep refs, while maintaining the ref - * reactivity: + * Note that the proxy object is not equal to the original object in the ES2015 + * Proxy-based implementation. It is **strongly** recommended to work + * exclusively with the reactive proxy and avoid relying on the original object. * + * @example * ```js * const count = ref(1) * const obj = reactive({ count }) * - * // ref will be unwrapped - * console.log(obj.count === count.value) // true + * console.log(obj.count) // 1 (ref is unwrapped, no need for .value) * - * // it will update `obj.count` + * // updating the ref will update `obj.count` * count.value++ - * console.log(count.value) // 2 * console.log(obj.count) // 2 * - * // it will also update `count` ref + * // updating the reactive property will update the ref, too * obj.count++ - * console.log(obj.count) // 3 * console.log(count.value) // 3 * ``` * - * **Important:** When assigning a ref to a reactive property, that ref will be - * automatically unwrapped: - * - * ```js - * const count = ref(1) - * const obj = reactive({}) - * - * obj.count = count - * - * console.log(obj.count) // 1 - * console.log(obj.count === count.value) // true - * ``` + * @param target The source object. */ export function reactive(target: T): UnwrapNestedRefs export function reactive(target: object) { @@ -126,28 +113,19 @@ export declare const ShallowReactiveMarker: unique symbol export type ShallowReactive = T & { [ShallowReactiveMarker]?: true } /** - * Returns a shallowly-reactive copy of the original object. + * Creates a shallowly-reactive copy of the original object. * - * This proxy will track reactivity of its own properties but does not perform - * deep reactive conversion of nested objects (i.e. it exposes "raw" values). - * - * Unlike `reactive`, any property that uses a ref will **not** be automatically - * unwrapped by the proxy (even at the root level). + * Does **not** unwrap any nested refs. All nested values are presented "raw". * + * @example * ```js - * const state = shallowReactive({ - * foo: 1, - * nested: { - * bar: 2 - * } - * }) + * const count = ref(1) + * const obj = shallowReactive({ count }) * - * // mutating state's own properties is reactive - * state.foo++ - * // ...but does not convert nested objects - * isReactive(state.nested) // false - * state.nested.bar++ // non-reactive + * console.log(obj.count.value) // 1 (not unwrapped) * ``` + * + * @param target The source object. */ export function shallowReactive( target: T @@ -188,10 +166,12 @@ export type DeepReadonly = T extends Builtin /** * Creates a readonly copy of the original object. * - * Takes an object (reactive or plain) or a ref and returns a readonly proxy to - * the original. A readonly proxy is "deep": any nested property accessed will - * be readonly as well. + * All (deep) properties within the proxy object will be readonly, too. As with + * `reactive`, all (deep) refs will be unwrapped. The returned object will not + * be reactive by default, but already-reactive objects can be passed to + * `readonly`. * + * @example * ```js * const original = reactive({ count: 0 }) * @@ -209,22 +189,7 @@ export type DeepReadonly = T extends Builtin * copy.count++ // warning! * ``` * - * As with `reactive`, if any property uses a ref it will be automatically - * unwrapped when it is accessed via the proxy: - * - * ```js - * const raw = { - * count: ref(123) - *} - * - * const copy = readonly(raw) - * - * console.log(raw.count.value) // 123 - * console.log(copy.count) // 123 - * ``` - * - * Note: The returned copy is not made reactive, but `readonly` can be called on - * an already reactive object. + * @param target The source object. */ export function readonly( target: T @@ -239,11 +204,12 @@ export function readonly( } /** - * Returns a shallowly-reactive copy of the original object. + * Returns a shallowly-reactive readonly copy of the original object. * - * Creates a proxy that makes its own properties readonly, but does not perform - * deep readonly conversion of nested objects (exposes raw values). + * All nested values are presented "raw". This means that **neither** nested + * values are made readonly **nor** nested refs are unwrapped. * + * @example * ```js * const state = shallowReadonly({ * foo: 1, @@ -259,10 +225,9 @@ export function readonly( * state.nested.bar++ // works * ``` * - * Unlike `readonly`, any property that uses a ref will **not** be automatically - * unwrapped by the proxy. + * @remarks This is used for creating the props proxy object for stateful components. * - * This is used for creating the props proxy object for stateful components. + * @param target The source object. */ export function shallowReadonly(target: T): Readonly { return createReactiveObject( @@ -316,40 +281,10 @@ function createReactiveObject( /** * Checks if an object is a reactive proxy created by `reactive`. * - * ```js - * import { reactive, isReactive } from 'vue' - * export default { - * setup() { - * const state = reactive({ - * name: 'John' - * }) - * console.log(isReactive(state)) // -> true - * } - * } - * ``` - * - * It also returns `true` if the proxy is created by `readonly`, but is + * It also returns `true` if the given object was created by `readonly`, but is * wrapping another proxy created by `reactive`. * - * ```js - * import { reactive, isReactive, readonly } from 'vue' - * export default { - * setup() { - * const state = reactive({ - * name: 'John' - * }) - * // readonly proxy created from plain object - * const plain = readonly({ - * name: 'Mary' - * }) - * console.log(isReactive(plain)) // -> false - * - * // readonly proxy created from reactive proxy - * const stateCopy = readonly(state) - * console.log(isReactive(stateCopy)) // -> true - * } - * } - * ``` + * @param value The value to check. */ export function isReactive(value: unknown): boolean { if (isReadonly(value)) { @@ -360,6 +295,8 @@ export function isReactive(value: unknown): boolean { /** * Checks if an object is a readonly proxy created by `readonly`. + * + * @param value The value to check. */ export function isReadonly(value: unknown): boolean { return !!(value && (value as Target)[ReactiveFlags.IS_READONLY]) @@ -371,6 +308,8 @@ export function isShallow(value: unknown): boolean { /** * Checks if an object is a proxy created by `reactive` or `readonly`. + * + * @param value The value to check. */ export function isProxy(value: unknown): boolean { return isReactive(value) || isReadonly(value) @@ -384,12 +323,15 @@ export function isProxy(value: unknown): boolean { * It is **not** recommended to hold a persistent reference to the original * object. Use with caution. * + * @example * ```js * const foo = {} * const reactiveFoo = reactive(foo) * * console.log(toRaw(reactiveFoo) === foo) // true * ``` + * + * @param observed The object for which the "raw" value is requested. */ export function toRaw(observed: T): T { const raw = observed && (observed as Target)[ReactiveFlags.RAW] @@ -401,8 +343,14 @@ export type Raw = T & { [RawSymbol]?: true } /** * Marks an object so that it will never be converted to a proxy. * - * Returns the object itself. + * **Warning:** This together with the `shallowXXX` APIs allow you to opt-out of + * the default deep reactive/readonly conversion. This has its uses but must be + * used in caution or you might end up with in raw, non-proxied objects in + * places where you might not expect them. * + * Returns the original object itself. + * + * @example * ```js * const foo = markRaw({}) * console.log(isReactive(reactive(foo))) // false @@ -412,38 +360,7 @@ export type Raw = T & { [RawSymbol]?: true } * console.log(isReactive(bar.foo)) // false * ``` * - * **Warning:** `markRaw` and the `shallowXXX` APIs below allow you to - * selectively opt-out of the default deep reactive/readonly conversion and - * embed raw, non-proxied objects in your state graph. They can be used for - * various reasons: - * - * * Some values simply should not be made reactive, for example a complex 3rd - * party class instance, or a Vue component object. - * * Skipping proxy conversion can provide performance improvements when - * rendering large lists with immutable data sources. - * - * They are considered advanced because the raw opt-out is only at the root - * level, so if you set a nested, non-marked raw object into a reactive object - * and then access it again, you get the proxied version back. This can lead to - * **identity hazards** - i.e. performing an operation that relies on object - * identity but using both the raw and the proxied version of the same object: - * - * ```js - * const foo = markRaw({ - * nested: {} - * }) - * - * const bar = reactive({ - * // although `foo` is marked as raw, foo.nested is not. - * nested: foo.nested - * }) - * - * console.log(foo.nested === bar.nested) // false - * ``` - * - * Identity hazards are in general rare. However, to properly utilize these APIs - * while safely avoiding identity hazards requires a solid understanding of how - * the reactivity system works. + * @param value The object to be marked as "raw". */ export function markRaw(value: T): Raw { def(value, ReactiveFlags.SKIP, true) @@ -454,6 +371,8 @@ export function markRaw(value: T): Raw { * Returns a reactive proxy of the given value (if possible). * * If the given value is not an object, the original value itself is returned. + * + * @param value The value for which a reactive proxy shall be created. */ export const toReactive = (value: T): T => isObject(value) ? reactive(value) : value @@ -462,6 +381,8 @@ export const toReactive = (value: T): T => * Returns a readonly proxy of the given value (if possible). * * If the given value is not an object, the original value itself is returned. + * + * @param value The value for which a readonly proxy shall be created. */ export const toReadonly = (value: T): T => isObject(value) ? readonly(value as Record) : value diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 45eab6d14c0..f37690613ab 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -71,6 +71,8 @@ export function triggerRefValue(ref: RefBase, newVal?: any) { /** * Checks if a value is a ref object. + * + * @param r The value to inspect. */ export function isRef(r: Ref | unknown): r is Ref export function isRef(r: any): r is Ref { @@ -78,50 +80,28 @@ export function isRef(r: any): r is Ref { } /** - * Takes an object as inner value and returns a reactive and mutable ref object. - * - * The ref object has a single `value` property that points to the inner value. - * The object is made deeply reactive by the `reactive` function. + * Creates a mutable reactive ref object from the given "inner value". * - * If the type of the generic is unknown, it's recommended to cast ref to - * `Ref`: + * The ref object has a single `value` property that is a proxy to the inner + * value created by the `reactive` function. * - * ```ts - * function useState(initial: State) { - * const state = ref(initial) as Ref // state.value -> State extends string - * return state - * } - * ``` + * @param value The object to wrap in the ref. */ export function ref( value: T ): [T] extends [Ref] ? T : Ref> /** - * Takes an inner value and returns a reactive and mutable ref object. + * Creates a mutable reactive ref object from the given "inner value". * * The ref object has a single `value` property that points to the inner value. * - * ```js - * const count = ref(0) - * console.log(count.value) // 0 - * count.value++ - * console.log(count.value) // 1 - * ``` - * - * Sometimes we may need to specify complex types for a ref's inner value. We - * can do that succinctly by passing a generics argument when calling `ref` to - * override the default inference: - * - * ```ts - * const foo = ref('foo') // foo's type: Ref - * foo.value = 123 // ok! - * ``` + * @param value The value to wrap in the ref. */ export function ref(value: T): Ref> /** - * Takes an inner value and returns a reactive and mutable ref object. + * Creates a mutable reactive ref object. * - * The ref has a single `value` property that points to the inner value. + * The ref has a single `value` property that can be written to. */ export function ref(): Ref export function ref(value?: unknown) { @@ -136,6 +116,7 @@ export type ShallowRef = Ref & { [ShallowRefMarker]?: true } * Creates a ref that tracks mutations on its own `value` but doesn't make its * value reactive. * + * @example * ```js * const foo = shallowRef({}) * // mutating the ref's value is reactive @@ -144,7 +125,9 @@ export type ShallowRef = Ref & { [ShallowRefMarker]?: true } * isReactive(foo.value) // false * ``` * - * See also: https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs + * @see {@link https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs} + * + * @param value The "inner value" for the shallow ref. */ export function shallowRef( value: T @@ -153,6 +136,7 @@ export function shallowRef( * Creates a ref that tracks mutations on its own `value` but doesn't make its * value reactive. * + * @example * ```js * const foo = shallowRef({}) * // mutating the ref's value is reactive @@ -161,22 +145,16 @@ export function shallowRef( * isReactive(foo.value) // false * ``` * - * See also: https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs + * @see {@link https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs} + * + * @param value The "inner value" for the shallow ref. */ export function shallowRef(value: T): ShallowRef /** * Creates a ref that tracks mutations on its own `value` but doesn't make its * value reactive. * - * ```js - * const foo = shallowRef({}) - * // mutating the ref's value is reactive - * foo.value = {} - * // but the value will not be converted. - * isReactive(foo.value) // false - * ``` - * - * See also: https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs + * @see {@link https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs} */ export function shallowRef(): ShallowRef export function shallowRef(value?: unknown) { @@ -222,6 +200,7 @@ class RefImpl { /** * Execute any effects tied to a shallow ref manually. * + * @example * ```js * const shallow = shallowRef({ * greet: 'Hello, world' @@ -239,7 +218,9 @@ class RefImpl { * triggerRef(shallow) * ``` * - * See also: https://v3.vuejs.org/api/computed-watch-api.html#watcheffect + * @see {@link https://v3.vuejs.org/api/computed-watch-api.html#watcheffect} + * + * @param ref The ref whose tied effects shall be executed. */ export function triggerRef(ref: Ref) { triggerRefValue(ref, __DEV__ ? ref.value : void 0) @@ -251,11 +232,14 @@ export function triggerRef(ref: Ref) { * * This is a sugar function for `val = isRef(val) ? val.value : val`. * + * @example * ```js * function useFoo(x: number | Ref) { * const unwrapped = unref(x) // unwrapped is guaranteed to be number now * } * ``` + * + * @param ref Ref or plain value to be converted into the plain value. */ export function unref(ref: T | Ref): T { return isRef(ref) ? (ref.value as any) : ref @@ -275,7 +259,7 @@ const shallowUnwrapHandlers: ProxyHandler = { } /** - * todo: document? This is published in vue-core, as well! + * todo: document? This is used in vue-core's component.ts */ export function proxyRefs( objectWithRefs: T @@ -326,8 +310,8 @@ class CustomRefImpl { * It expects a factory function, which receives `track` and `trigger` functions * as arguments and should return an object with `get` and `set`. * - * Example using a custom ref to implement debounce with `v-model`: - * + * @example + * Using a custom ref to implement debounce with `v-model`: * ```js * // in the template: * @@ -358,6 +342,8 @@ class CustomRefImpl { * } * } * ``` + * + * @param factory The function that receives the `track` and `trigger` callbacks. */ export function customRef(factory: CustomRefFactory): Ref { return new CustomRefImpl(factory) as any @@ -368,10 +354,9 @@ export type ToRefs = { } /** - * Converts a reactive object to a plain object where each property of the - * resulting object is a ref pointing to the corresponding property of the - * original object. + * Creates an object of refs pointing to the given reactive object's properties. * + * @example * ```js * const state = reactive({ * foo: 1, @@ -380,47 +365,9 @@ export type ToRefs = { * * // type of stateAsRefs: { foo: Ref, bar: Ref } * const stateAsRefs = toRefs(state) - * - * // The ref and the original property is "linked" - * state.foo++ - * console.log(stateAsRefs.foo.value) // 2 - * - * stateAsRefs.foo.value++ - * console.log(state.foo) // 3 - * ``` - * - * `toRefs` is useful when returning a reactive object from a composition - * function so that the consuming component can destructure/spread the returned - * object without losing reactivity: - * - * ```js - * function useFeatureX() { - * const state = reactive({ - * foo: 1, - * bar: 2 - * }) - * - * // logic operating on state - * - * // convert to refs when returning - * return toRefs(state) - * } - * - * export default { - * setup() { - * // can destructure without losing reactivity - * const { foo, bar } = useFeatureX() - * - * return { - * foo, - * bar - * } - * } - * } * ``` * - * `toRefs` will only generate refs for properties that are included in the - * source object. To create a ref for a specific property use `toRef` instead. + * @param object Reactive object to be made into an object of linked refs. */ export function toRefs(object: T): ToRefs { if (__DEV__ && !isProxy(object)) { @@ -459,11 +406,9 @@ class ObjectRefImpl { export type ToRef = IfAny, [T] extends [Ref] ? T : Ref> /** - * Can be used to create a ref for a property on a source reactive object. - * - * The ref can then be passed around, retaining the reactive connection to its - * source property. + * Creates a linked ref from a reactive object's property. * + * @example * ```js * const state = reactive({ * foo: 1, @@ -479,20 +424,12 @@ export type ToRef = IfAny, [T] extends [Ref] ? T : Ref> * console.log(fooRef.value) // 3 * ``` * - * `toRef` is useful when you want to pass the ref of a prop to a composition - * function: - * - * ```js - * export default { - * setup(props) { - * useSomeFeature(toRef(props, 'foo')) - * } - * } - * ``` - * * `toRef` will return a usable ref even if the source property doesn't * currently exist. This makes it especially useful when working with optional * props, which wouldn't be picked up by `toRefs`. + * + * @param object The reactive object containing the desired property. + * @param key Name of the property in the reactive object. */ export function toRef( object: T, From d7933ce4d8e84aa55c9d44b9cb978125d0878f17 Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Fri, 22 Oct 2021 23:51:48 +0200 Subject: [PATCH 03/18] Drop empty @param tags as they don't behave in VSCode --- packages/reactivity/src/computed.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index 277f161f979..c18a909b5f4 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -83,7 +83,6 @@ export class ComputedRefImpl { * ``` * * @param getter Function that produces the next value. - * @param debugOptions */ export function computed( getter: ComputedGetter, @@ -109,7 +108,6 @@ export function computed( * ``` * * @param options Object holding the `get` and `set` functions. - * @param debugOptions */ export function computed( options: WritableComputedOptions, From 80c87e8917dddc5825b54cb0e02a0d39c40c61f2 Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Mon, 25 Oct 2021 23:29:41 +0200 Subject: [PATCH 04/18] Add a few more function docs --- packages/reactivity/src/effect.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 130fc863f4f..c77af6b544d 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -167,6 +167,16 @@ export interface ReactiveEffectRunner { effect: ReactiveEffect } +/** + * Registers the given function to track reactive updates. + * + * The given function will be run once immediately. Every time any reactive + * property that's accessed within it gets updated, the function will run again. + * + * @param fn The function that will track reactive updates. + * @param options Allows to control the effect's behaviour. + * @returns A runner that can be used to control the effect. + */ export function effect( fn: () => T, options?: ReactiveEffectOptions @@ -188,6 +198,11 @@ export function effect( return runner } +/** + * Stops the effect associated with the given runner. + * + * @param runner Association with the effect to stop tracking. + */ export function stop(runner: ReactiveEffectRunner) { runner.effect.stop() } @@ -195,16 +210,25 @@ export function stop(runner: ReactiveEffectRunner) { export let shouldTrack = true const trackStack: boolean[] = [] +/** + * Temporarily pauses tracking. + */ export function pauseTracking() { trackStack.push(shouldTrack) shouldTrack = false } +/** + * Re-enables effect tracking (if it was paused). + */ export function enableTracking() { trackStack.push(shouldTrack) shouldTrack = true } +/** + * Resets the previous global effect tracking state. + */ export function resetTracking() { const last = trackStack.pop() shouldTrack = last === undefined ? true : last From 2421d18b8b2eb00c7a5abf0b6698f60e9dfaa9ce Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Sun, 7 Nov 2021 16:31:54 +0100 Subject: [PATCH 05/18] Update / add a few docs in effect.ts --- packages/reactivity/src/effect.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index c77af6b544d..2f52b4fc648 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -175,7 +175,7 @@ export interface ReactiveEffectRunner { * * @param fn The function that will track reactive updates. * @param options Allows to control the effect's behaviour. - * @returns A runner that can be used to control the effect. + * @returns A runner that can be used to control the effect after creation. */ export function effect( fn: () => T, @@ -234,6 +234,16 @@ export function resetTracking() { shouldTrack = last === undefined ? true : last } +/** + * Tracks access to a reactive property. + * + * This will check which effect is running at the moment and record it as dep + * which records all effects that depend on the reactive property. + * + * @param target Object holding the reactive property. + * @param type Defines the type of access to the reactive property. + * @param key Identifier of the reactive property. + */ export function track(target: object, type: TrackOpTypes, key: unknown) { if (shouldTrack && activeEffect) { let depsMap = targetMap.get(target) @@ -284,6 +294,14 @@ export function trackEffects( } } +/** + * Finds all deps associated with the target (or a specific property) and + * triggers the effects stored within. + * + * @param target The reactive object. + * @param type Defines the type of the operation that needs to trigger effects. + * @param key Can be used to target a specific reactive property in the target object. + */ export function trigger( target: object, type: TriggerOpTypes, From 8ea1d42bd99f73ec4fc0cb58e6ec3c8c701cc4f6 Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Sun, 7 Nov 2021 17:51:24 +0100 Subject: [PATCH 06/18] Update / add a few docs in effectScope.ts --- packages/reactivity/src/effectScope.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index c644d03fae6..a4544aaf115 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -107,6 +107,13 @@ export class EffectScope { } } +/** + * Creates a new effect scope that allows automatic collection and disposal of + * a group of effects. + * + * @see {@link https://github.com/vuejs/rfcs/pull/212} + * @param detached Can be used to create a "detached" effect scope. + */ export function effectScope(detached?: boolean) { return new EffectScope(detached) } @@ -120,10 +127,23 @@ export function recordEffectScope( } } +/** + * Provides access to the current effect scope. + * + * This may be undefined at times when there's no effect active effect scope at + * this very moment. + */ export function getCurrentScope() { return activeEffectScope } +/** + * Allows to add a callback to the current effect scope's cleanup. + * + * If there is no active effect scope at the moment, this will do nothing. + * + * @param fn The callback function to attach to the scope's cleanup. + */ export function onScopeDispose(fn: () => void) { if (activeEffectScope) { activeEffectScope.cleanups.push(fn) From 014bf680d35f9ab2ee1f936bf29b3466f7925145 Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Sun, 7 Nov 2021 18:02:21 +0100 Subject: [PATCH 07/18] Add doc for `proxyRefs` --- packages/reactivity/src/ref.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index f37690613ab..8c4088cbf20 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -259,7 +259,14 @@ const shallowUnwrapHandlers: ProxyHandler = { } /** - * todo: document? This is used in vue-core's component.ts + * Returns a reactive proxy for the given object. + * + * If the object already is reactive, it's returned as-is. If not, a new + * reactive proxy is created. Direct child properties that are refs are properly + * handled, as well. + * + * @param objectWithRefs Either an already-reactive object or a simple object + * that contains refs. */ export function proxyRefs( objectWithRefs: T From 7421698b07538d0cf12dcb537842f896cffc366b Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Mon, 30 Jan 2023 10:14:27 +0100 Subject: [PATCH 08/18] Update packages/reactivity/src/effect.ts Co-authored-by: Eduardo San Martin Morote --- packages/reactivity/src/effect.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 2f52b4fc648..1dd2fb6b017 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -242,7 +242,7 @@ export function resetTracking() { * * @param target Object holding the reactive property. * @param type Defines the type of access to the reactive property. - * @param key Identifier of the reactive property. + * @param key Identifier of the reactive property to track. */ export function track(target: object, type: TrackOpTypes, key: unknown) { if (shouldTrack && activeEffect) { From 8c80de95026ea9c3a0f9deb676d42d34389158fe Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Mon, 30 Jan 2023 10:17:22 +0100 Subject: [PATCH 09/18] Update packages/reactivity/src/effectScope.ts Co-authored-by: Eduardo San Martin Morote --- packages/reactivity/src/effectScope.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index a4544aaf115..fb663c45d9e 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -108,8 +108,9 @@ export class EffectScope { } /** - * Creates a new effect scope that allows automatic collection and disposal of - * a group of effects. + * Creates an effect scope object which can capture the reactive effects + * (i.e. computed and watchers) created within it so that these effects + * can be disposed of together. * * @see {@link https://github.com/vuejs/rfcs/pull/212} * @param detached Can be used to create a "detached" effect scope. From d07d25b20f6f2e650767ef7eb43296950b7bf437 Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Mon, 30 Jan 2023 10:20:38 +0100 Subject: [PATCH 10/18] Update packages/reactivity/src/ref.ts Co-authored-by: Eduardo San Martin Morote --- packages/reactivity/src/ref.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 8c4088cbf20..76157f85391 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -125,7 +125,7 @@ export type ShallowRef = Ref & { [ShallowRefMarker]?: true } * isReactive(foo.value) // false * ``` * - * @see {@link https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs} + * @see {@link https://vuejs.org/guide/essentials/reactivity-fundamentals.html} * * @param value The "inner value" for the shallow ref. */ From 5706783404a26b970da2e7e510398bd232a12b2a Mon Sep 17 00:00:00 2001 From: defaude Date: Sun, 5 Feb 2023 22:26:43 +0100 Subject: [PATCH 11/18] chore: Add description for computed debugOptions --- packages/reactivity/src/computed.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index c18a909b5f4..b821f038058 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -83,6 +83,7 @@ export class ComputedRefImpl { * ``` * * @param getter Function that produces the next value. + * @param debugOptions For debugging. See https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging. */ export function computed( getter: ComputedGetter, @@ -108,6 +109,7 @@ export function computed( * ``` * * @param options Object holding the `get` and `set` functions. + * @param debugOptions For debugging. See https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging. */ export function computed( options: WritableComputedOptions, From 4c7fbe29c0bb57ce75d9c8039ea0bd0cd2951913 Mon Sep 17 00:00:00 2001 From: defaude Date: Sun, 5 Feb 2023 22:28:11 +0100 Subject: [PATCH 12/18] chore: doc format --- packages/reactivity/src/effectScope.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index fb663c45d9e..7d0240d77c6 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -139,9 +139,8 @@ export function getCurrentScope() { } /** - * Allows to add a callback to the current effect scope's cleanup. - * - * If there is no active effect scope at the moment, this will do nothing. + * Allows to add a callback to the current effect scope's cleanup. If there is + * no active effect scope at the moment, this will do nothing. * * @param fn The callback function to attach to the scope's cleanup. */ From 40eaaef89bc2abcd2d274fe6112473ac335b765f Mon Sep 17 00:00:00 2001 From: defaude Date: Sun, 5 Feb 2023 22:37:08 +0100 Subject: [PATCH 13/18] chore: reuse docs from docs website --- packages/reactivity/src/ref.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 76157f85391..789f5bd3385 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -198,7 +198,10 @@ class RefImpl { } /** - * Execute any effects tied to a shallow ref manually. + * Force trigger effects that depends on a shallow ref. + * + * This is typically used after making deep mutations to the inner value of a + * shallow ref. * * @example * ```js @@ -361,7 +364,9 @@ export type ToRefs = { } /** - * Creates an object of refs pointing to the given reactive object's properties. + * Converts a reactive object to a plain object where each property of the + * resulting object is a ref pointing to the corresponding property of the + * original object. Each individual ref is created using toRef(). * * @example * ```js @@ -413,7 +418,10 @@ class ObjectRefImpl { export type ToRef = IfAny, [T] extends [Ref] ? T : Ref> /** - * Creates a linked ref from a reactive object's property. + * Can be used to create a ref for a property on a source reactive object. + * + * The created ref is synced with its source property: mutating the source + * property will update the ref, and vice-versa. * * @example * ```js From 234a7f13b63cfec8330591bb9fa5ecab2279cd4d Mon Sep 17 00:00:00 2001 From: defaude Date: Wed, 8 Feb 2023 17:46:25 +0100 Subject: [PATCH 14/18] chore: remove doc dupes on overloaded functions --- packages/reactivity/src/ref.ts | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 789f5bd3385..8e4023af605 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -132,30 +132,7 @@ export type ShallowRef = Ref & { [ShallowRefMarker]?: true } export function shallowRef( value: T ): T extends Ref ? T : ShallowRef -/** - * Creates a ref that tracks mutations on its own `value` but doesn't make its - * value reactive. - * - * @example - * ```js - * const foo = shallowRef({}) - * // mutating the ref's value is reactive - * foo.value = {} - * // but the value will not be converted. - * isReactive(foo.value) // false - * ``` - * - * @see {@link https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs} - * - * @param value The "inner value" for the shallow ref. - */ export function shallowRef(value: T): ShallowRef -/** - * Creates a ref that tracks mutations on its own `value` but doesn't make its - * value reactive. - * - * @see {@link https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs} - */ export function shallowRef(): ShallowRef export function shallowRef(value?: unknown) { return createRef(value, true) From b90f4e0eadb27dfbc2138ef96d7eed446a35686c Mon Sep 17 00:00:00 2001 From: Roland Hummel Date: Fri, 17 Feb 2023 13:36:54 +0100 Subject: [PATCH 15/18] Apply suggestions from code review Co-authored-by: Eduardo San Martin Morote --- packages/reactivity/src/reactive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index 965d5ee638c..c2ff28eb2c4 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -65,7 +65,7 @@ function getTargetType(value: Target) { export type UnwrapNestedRefs = T extends Ref ? T : UnwrapRefSimple /** - * Creates a deeply-reactive copy of the original object. + * Returns a reactive proxy of the object. * * All (deep) refs within the object will be unwrapped, while maintaining the * ref's reactivity. This is also done for refs that are assigned after creation From e6f6cf8cec744b96f460fa3aef95de3e5d5a8782 Mon Sep 17 00:00:00 2001 From: defaude Date: Sat, 18 Feb 2023 15:24:34 +0100 Subject: [PATCH 16/18] chore: Update doc blocks with links to docs page Also shorten doc blocks a bit, remove overly-long examples etc. --- packages/reactivity/src/computed.ts | 6 +- packages/reactivity/src/effectScope.ts | 19 ++-- packages/reactivity/src/reactive.ts | 135 +++++++++++++++---------- packages/reactivity/src/ref.ts | 123 ++++++---------------- 4 files changed, 126 insertions(+), 157 deletions(-) diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index b821f038058..f8aad739d81 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -83,7 +83,8 @@ export class ComputedRefImpl { * ``` * * @param getter Function that produces the next value. - * @param debugOptions For debugging. See https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging. + * @param debugOptions For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}. + * @see {@link https://vuejs.org/api/reactivity-core.html#computed} */ export function computed( getter: ComputedGetter, @@ -109,7 +110,8 @@ export function computed( * ``` * * @param options Object holding the `get` and `set` functions. - * @param debugOptions For debugging. See https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging. + * @param debugOptions For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}. + * @see {@link https://vuejs.org/api/reactivity-core.html#computed} */ export function computed( options: WritableComputedOptions, diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index 7d0240d77c6..9ab52906e14 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -108,12 +108,13 @@ export class EffectScope { } /** - * Creates an effect scope object which can capture the reactive effects - * (i.e. computed and watchers) created within it so that these effects - * can be disposed of together. + * Creates an effect scope object which can capture the reactive effects (i.e. + * computed and watchers) created within it so that these effects can be + * disposed together. For detailed use cases of this API, please consult its + * corresponding {@link https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md | RFC}. * - * @see {@link https://github.com/vuejs/rfcs/pull/212} * @param detached Can be used to create a "detached" effect scope. + * @see {@link https://vuejs.org/api/reactivity-advanced.html#effectscope} */ export function effectScope(detached?: boolean) { return new EffectScope(detached) @@ -129,20 +130,20 @@ export function recordEffectScope( } /** - * Provides access to the current effect scope. + * Returns the current active effect scope if there is one. * - * This may be undefined at times when there's no effect active effect scope at - * this very moment. + * @see {@link https://vuejs.org/api/reactivity-advanced.html#getcurrentscope} */ export function getCurrentScope() { return activeEffectScope } /** - * Allows to add a callback to the current effect scope's cleanup. If there is - * no active effect scope at the moment, this will do nothing. + * Registers a dispose callback on the current active effect scope. The + * callback will be invoked when the associated effect scope is stopped. * * @param fn The callback function to attach to the scope's cleanup. + * @see {@link https://vuejs.org/api/reactivity-advanced.html#onscopedispose} */ export function onScopeDispose(fn: () => void) { if (activeEffectScope) { diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index c2ff28eb2c4..d588019c559 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -65,33 +65,19 @@ function getTargetType(value: Target) { export type UnwrapNestedRefs = T extends Ref ? T : UnwrapRefSimple /** - * Returns a reactive proxy of the object. + * Creates a deeply-reactive copy of the original object. * - * All (deep) refs within the object will be unwrapped, while maintaining the - * ref's reactivity. This is also done for refs that are assigned after creation - * of the proxy object. - * - * Note that the proxy object is not equal to the original object in the ES2015 - * Proxy-based implementation. It is **strongly** recommended to work - * exclusively with the reactive proxy and avoid relying on the original object. + * The reactive conversion is "deep": it affects all nested properties. A + * reactive object also deeply unwraps any properties that are refs while + * maintaining reactivity. * * @example * ```js - * const count = ref(1) - * const obj = reactive({ count }) - * - * console.log(obj.count) // 1 (ref is unwrapped, no need for .value) - * - * // updating the ref will update `obj.count` - * count.value++ - * console.log(obj.count) // 2 - * - * // updating the reactive property will update the ref, too - * obj.count++ - * console.log(count.value) // 3 + * const obj = reactive({ count: 0 }) * ``` * * @param target The source object. + * @see {@link https://vuejs.org/api/reactivity-core.html#reactive} */ export function reactive(target: T): UnwrapNestedRefs export function reactive(target: object) { @@ -113,19 +99,34 @@ export declare const ShallowReactiveMarker: unique symbol export type ShallowReactive = T & { [ShallowReactiveMarker]?: true } /** - * Creates a shallowly-reactive copy of the original object. + * Shallow version of {@link reactive()}. * - * Does **not** unwrap any nested refs. All nested values are presented "raw". + * Unlike {@link reactive()}, there is no deep conversion: only root-level + * properties are reactive for a shallow reactive object. Property values are + * stored and exposed as-is - this also means properties with ref values will + * not be automatically unwrapped. * * @example * ```js - * const count = ref(1) - * const obj = shallowReactive({ count }) + * const state = shallowReactive({ + * foo: 1, + * nested: { + * bar: 2 + * } + * }) + * + * // mutating state's own properties is reactive + * state.foo++ + * + * // ...but does not convert nested objects + * isReactive(state.nested) // false * - * console.log(obj.count.value) // 1 (not unwrapped) + * // NOT reactive + * state.nested.bar++ * ``` * * @param target The source object. + * @see {@link https://vuejs.org/api/reactivity-advanced.html#shallowreactive} */ export function shallowReactive( target: T @@ -164,12 +165,12 @@ export type DeepReadonly = T extends Builtin : Readonly /** - * Creates a readonly copy of the original object. + * Takes an object (reactive or plain) or a ref and returns a readonly proxy to + * the original. * - * All (deep) properties within the proxy object will be readonly, too. As with - * `reactive`, all (deep) refs will be unwrapped. The returned object will not - * be reactive by default, but already-reactive objects can be passed to - * `readonly`. + * A readonly proxy is deep: any nested property accessed will be readonly as + * well. It also has the same ref-unwrapping behavior as {@link reactive()}, + * except the unwrapped values will also be made readonly. * * @example * ```js @@ -190,6 +191,7 @@ export type DeepReadonly = T extends Builtin * ``` * * @param target The source object. + * @see {@link https://vuejs.org/api/reactivity-core.html#readonly} */ export function readonly( target: T @@ -204,10 +206,12 @@ export function readonly( } /** - * Returns a shallowly-reactive readonly copy of the original object. + * Shallow version of {@link readonly()}. * - * All nested values are presented "raw". This means that **neither** nested - * values are made readonly **nor** nested refs are unwrapped. + * Unlike {@link readonly()}, there is no deep conversion: only root-level + * properties are made readonly. Property values are stored and exposed as-is - + * this also means properties with ref values will not be automatically + * unwrapped. * * @example * ```js @@ -220,14 +224,16 @@ export function readonly( * * // mutating state's own properties will fail * state.foo++ + * * // ...but works on nested objects * isReadonly(state.nested) // false - * state.nested.bar++ // works - * ``` * - * @remarks This is used for creating the props proxy object for stateful components. + * // works + * state.nested.bar++ + * ``` * * @param target The source object. + * @see {@link https://vuejs.org/api/reactivity-advanced.html#shallowreadonly} */ export function shallowReadonly(target: T): Readonly { return createReactiveObject( @@ -279,12 +285,22 @@ function createReactiveObject( } /** - * Checks if an object is a reactive proxy created by `reactive`. + * Checks if an object is a proxy created by {@link reactive()} or + * {@link shallowReactive()} (or {@link ref()} in some cases). * - * It also returns `true` if the given object was created by `readonly`, but is - * wrapping another proxy created by `reactive`. + * @example + * ```js + * isReactive(reactive({})) // => true + * isReactive(readonly(reactive({}))) // => true + * isReactive(ref({}).value) // => true + * isReactive(readonly(ref({})).value) // => true + * isReactive(ref(true)) // => false + * isReactive(shallowRef({}).value) // => false + * isReactive(shallowReactive({})) // => true + * ``` * * @param value The value to check. + * @see {@link https://vuejs.org/api/reactivity-utilities.html#isreactive} */ export function isReactive(value: unknown): boolean { if (isReadonly(value)) { @@ -294,9 +310,15 @@ export function isReactive(value: unknown): boolean { } /** - * Checks if an object is a readonly proxy created by `readonly`. + * Checks whether the passed value is a readonly object. The properties of a + * readonly object can change, but they can't be assigned directly via the + * passed object. + * + * The proxies created by {@link readonly()} and {@link shallowReadonly()} are + * both considered readonly, as is a computed ref without a set function. * * @param value The value to check. + * @see {@link https://vuejs.org/api/reactivity-utilities.html#isreadonly} */ export function isReadonly(value: unknown): boolean { return !!(value && (value as Target)[ReactiveFlags.IS_READONLY]) @@ -307,21 +329,27 @@ export function isShallow(value: unknown): boolean { } /** - * Checks if an object is a proxy created by `reactive` or `readonly`. + * Checks if an object is a proxy created by {@link reactive}, + * {@link readonly}, {@link shallowReactive} or {@link shallowReadonly()}. * * @param value The value to check. + * @see {@link https://vuejs.org/api/reactivity-utilities.html#isproxy} */ export function isProxy(value: unknown): boolean { return isReactive(value) || isReadonly(value) } /** - * Returns the raw, original object of a reactive or readonly proxy. + * Returns the raw, original object of a Vue-created proxy. + * + * `toRaw()` can return the original object from proxies created by + * {@link reactive()}, {@link readonly()}, {@link shallowReactive()} or + * {@link shallowReadonly()}. * * This is an escape hatch that can be used to temporarily read without - * incurring proxy access/tracking overhead or write without triggering changes. - * It is **not** recommended to hold a persistent reference to the original - * object. Use with caution. + * incurring proxy access / tracking overhead or write without triggering + * changes. It is **not** recommended to hold a persistent reference to the + * original object. Use with caution. * * @example * ```js @@ -332,6 +360,7 @@ export function isProxy(value: unknown): boolean { * ``` * * @param observed The object for which the "raw" value is requested. + * @see {@link https://vuejs.org/api/reactivity-advanced.html#toraw} */ export function toRaw(observed: T): T { const raw = observed && (observed as Target)[ReactiveFlags.RAW] @@ -341,14 +370,8 @@ export function toRaw(observed: T): T { export type Raw = T & { [RawSymbol]?: true } /** - * Marks an object so that it will never be converted to a proxy. - * - * **Warning:** This together with the `shallowXXX` APIs allow you to opt-out of - * the default deep reactive/readonly conversion. This has its uses but must be - * used in caution or you might end up with in raw, non-proxied objects in - * places where you might not expect them. - * - * Returns the original object itself. + * Marks an object so that it will never be converted to a proxy. Returns the + * object itself. * * @example * ```js @@ -360,7 +383,13 @@ export type Raw = T & { [RawSymbol]?: true } * console.log(isReactive(bar.foo)) // false * ``` * + * **Warning:** `markRaw()` together with the shallow APIs such as + * {@link shallowReactive()} allow you to selectively opt-out of the default + * deep reactive/readonly conversion and embed raw, non-proxied objects in your + * state graph. + * * @param value The object to be marked as "raw". + * @see {@link https://vuejs.org/api/reactivity-advanced.html#markraw} */ export function markRaw(value: T): Raw { def(value, ReactiveFlags.SKIP, true) diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 8e4023af605..33db625dcf0 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -73,6 +73,7 @@ export function triggerRefValue(ref: RefBase, newVal?: any) { * Checks if a value is a ref object. * * @param r The value to inspect. + * @see {@link https://vuejs.org/api/reactivity-utilities.html#isref} */ export function isRef(r: Ref | unknown): r is Ref export function isRef(r: any): r is Ref { @@ -80,29 +81,16 @@ export function isRef(r: any): r is Ref { } /** - * Creates a mutable reactive ref object from the given "inner value". - * - * The ref object has a single `value` property that is a proxy to the inner - * value created by the `reactive` function. + * Takes an inner value and returns a reactive and mutable ref object, which + * has a single property `.value` that points to the inner value. * * @param value The object to wrap in the ref. + * @see {@link https://vuejs.org/api/reactivity-core.html#ref} */ export function ref( value: T ): [T] extends [Ref] ? T : Ref> -/** - * Creates a mutable reactive ref object from the given "inner value". - * - * The ref object has a single `value` property that points to the inner value. - * - * @param value The value to wrap in the ref. - */ export function ref(value: T): Ref> -/** - * Creates a mutable reactive ref object. - * - * The ref has a single `value` property that can be written to. - */ export function ref(): Ref export function ref(value?: unknown) { return createRef(value, false) @@ -113,21 +101,21 @@ declare const ShallowRefMarker: unique symbol export type ShallowRef = Ref & { [ShallowRefMarker]?: true } /** - * Creates a ref that tracks mutations on its own `value` but doesn't make its - * value reactive. + * Shallow version of {@link ref()}. * * @example * ```js - * const foo = shallowRef({}) - * // mutating the ref's value is reactive - * foo.value = {} - * // but the value will not be converted. - * isReactive(foo.value) // false - * ``` + * const state = shallowRef({ count: 1 }) * - * @see {@link https://vuejs.org/guide/essentials/reactivity-fundamentals.html} + * // does NOT trigger change + * state.value.count = 2 + * + * // does trigger change + * state.value = { count: 2 } + * ``` * * @param value The "inner value" for the shallow ref. + * @see {@link https://vuejs.org/api/reactivity-advanced.html#shallowref} */ export function shallowRef( value: T @@ -175,10 +163,8 @@ class RefImpl { } /** - * Force trigger effects that depends on a shallow ref. - * - * This is typically used after making deep mutations to the inner value of a - * shallow ref. + * Force trigger effects that depends on a shallow ref. This is typically used + * after making deep mutations to the inner value of a shallow ref. * * @example * ```js @@ -198,9 +184,8 @@ class RefImpl { * triggerRef(shallow) * ``` * - * @see {@link https://v3.vuejs.org/api/computed-watch-api.html#watcheffect} - * * @param ref The ref whose tied effects shall be executed. + * @see {@link https://vuejs.org/api/reactivity-advanced.html#triggerref} */ export function triggerRef(ref: Ref) { triggerRefValue(ref, __DEV__ ? ref.value : void 0) @@ -208,18 +193,19 @@ export function triggerRef(ref: Ref) { /** * Returns the inner value if the argument is a ref, otherwise return the - * argument itself. - * - * This is a sugar function for `val = isRef(val) ? val.value : val`. + * argument itself. This is a sugar function for + * `val = isRef(val) ? val.value : val`. * * @example * ```js * function useFoo(x: number | Ref) { - * const unwrapped = unref(x) // unwrapped is guaranteed to be number now + * const unwrapped = unref(x) + * // unwrapped is guaranteed to be number now * } * ``` * * @param ref Ref or plain value to be converted into the plain value. + * @see {@link https://vuejs.org/api/reactivity-utilities.html#unref} */ export function unref(ref: T | Ref): T { return isRef(ref) ? (ref.value as any) : ref @@ -294,43 +280,8 @@ class CustomRefImpl { * Creates a customized ref with explicit control over its dependency tracking * and updates triggering. * - * It expects a factory function, which receives `track` and `trigger` functions - * as arguments and should return an object with `get` and `set`. - * - * @example - * Using a custom ref to implement debounce with `v-model`: - * ```js - * // in the template: - * - * function useDebouncedRef(value, delay = 200) { - * let timeout - * return customRef((track, trigger) => { - * return { - * get() { - * track() - * return value - * }, - * set(newValue) { - * clearTimeout(timeout) - * timeout = setTimeout(() => { - * value = newValue - * trigger() - * }, delay) - * } - * } - * }) - * } - * - * export default { - * setup() { - * return { - * text: useDebouncedRef('hello') - * } - * } - * } - * ``` - * * @param factory The function that receives the `track` and `trigger` callbacks. + * @see {@link https://vuejs.org/api/reactivity-advanced.html#customref} */ export function customRef(factory: CustomRefFactory): Ref { return new CustomRefImpl(factory) as any @@ -343,20 +294,10 @@ export type ToRefs = { /** * Converts a reactive object to a plain object where each property of the * resulting object is a ref pointing to the corresponding property of the - * original object. Each individual ref is created using toRef(). - * - * @example - * ```js - * const state = reactive({ - * foo: 1, - * bar: 2 - * }) - * - * // type of stateAsRefs: { foo: Ref, bar: Ref } - * const stateAsRefs = toRefs(state) - * ``` + * original object. Each individual ref is created using {@link toRef()}. * * @param object Reactive object to be made into an object of linked refs. + * @see {@link https://vuejs.org/api/reactivity-utilities.html#torefs} */ export function toRefs(object: T): ToRefs { if (__DEV__ && !isProxy(object)) { @@ -395,10 +336,9 @@ class ObjectRefImpl { export type ToRef = IfAny, [T] extends [Ref] ? T : Ref> /** - * Can be used to create a ref for a property on a source reactive object. - * - * The created ref is synced with its source property: mutating the source - * property will update the ref, and vice-versa. + * Can be used to create a ref for a property on a source reactive object. The + * created ref is synced with its source property: mutating the source property + * will update the ref, and vice-versa. * * @example * ```js @@ -409,31 +349,28 @@ export type ToRef = IfAny, [T] extends [Ref] ? T : Ref> * * const fooRef = toRef(state, 'foo') * + * // mutating the ref updates the original * fooRef.value++ * console.log(state.foo) // 2 * + * // mutating the original also updates the ref * state.foo++ * console.log(fooRef.value) // 3 * ``` * - * `toRef` will return a usable ref even if the source property doesn't - * currently exist. This makes it especially useful when working with optional - * props, which wouldn't be picked up by `toRefs`. - * * @param object The reactive object containing the desired property. * @param key Name of the property in the reactive object. + * @see {@link https://vuejs.org/api/reactivity-utilities.html#toref} */ export function toRef( object: T, key: K ): ToRef - export function toRef( object: T, key: K, defaultValue: T[K] ): ToRef> - export function toRef( object: T, key: K, From 03b3e96093ab5188b3edf7e09a25ffa99cc78fc6 Mon Sep 17 00:00:00 2001 From: defaude Date: Tue, 21 Feb 2023 08:17:55 +0100 Subject: [PATCH 17/18] chore: Align doc blocks of reactive() and computed() with online docs --- packages/reactivity/src/computed.ts | 30 +++++++++++------------------ packages/reactivity/src/reactive.ts | 2 +- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index f8aad739d81..83f9d4c8939 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -69,12 +69,13 @@ export class ComputedRefImpl { } /** - * Creates an immutable reactive ref object. - * - * The `getter` function's return value determines the ref's value. + * Takes a getter function and returns a readonly reactive ref object for the + * returned value from the getter. It can also take an object with get and set + * functions to create a writable ref object. * * @example * ```js + * // Creating a readonly computed ref: * const count = ref(1) * const plusOne = computed(() => count.value + 1) * @@ -82,25 +83,12 @@ export class ComputedRefImpl { * plusOne.value++ // error * ``` * - * @param getter Function that produces the next value. - * @param debugOptions For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}. - * @see {@link https://vuejs.org/api/reactivity-core.html#computed} - */ -export function computed( - getter: ComputedGetter, - debugOptions?: DebuggerOptions -): ComputedRef -/** - * Creates a writable ref object. - * - * The given object with `get` and `set` functions define the ref's behavior. - * - * @example * ```js + * // Creating a writable computed ref: * const count = ref(1) * const plusOne = computed({ * get: () => count.value + 1, - * set: val => { + * set: (val) => { * count.value = val - 1 * } * }) @@ -109,10 +97,14 @@ export function computed( * console.log(count.value) // 0 * ``` * - * @param options Object holding the `get` and `set` functions. + * @param getter Function that produces the next value. * @param debugOptions For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}. * @see {@link https://vuejs.org/api/reactivity-core.html#computed} */ +export function computed( + getter: ComputedGetter, + debugOptions?: DebuggerOptions +): ComputedRef export function computed( options: WritableComputedOptions, debugOptions?: DebuggerOptions diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index d588019c559..bc6c723e004 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -65,7 +65,7 @@ function getTargetType(value: Target) { export type UnwrapNestedRefs = T extends Ref ? T : UnwrapRefSimple /** - * Creates a deeply-reactive copy of the original object. + * Returns a reactive proxy of the object. * * The reactive conversion is "deep": it affects all nested properties. A * reactive object also deeply unwraps any properties that are refs while From 987c30c70533c377236d398d13ad7c6d52712b7a Mon Sep 17 00:00:00 2001 From: defaude Date: Tue, 21 Feb 2023 08:22:40 +0100 Subject: [PATCH 18/18] chore: Fix @param tag syntax to align with https://tsdoc.org/pages/tags/param/ --- packages/compiler-sfc/src/templateUtils.ts | 2 +- packages/reactivity/src/computed.ts | 4 ++-- packages/reactivity/src/effect.ts | 18 +++++++++--------- packages/reactivity/src/effectScope.ts | 4 ++-- packages/reactivity/src/reactive.ts | 22 +++++++++++----------- packages/reactivity/src/ref.ts | 20 ++++++++++---------- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/compiler-sfc/src/templateUtils.ts b/packages/compiler-sfc/src/templateUtils.ts index 3f4cb8f6caa..0966945a5ee 100644 --- a/packages/compiler-sfc/src/templateUtils.ts +++ b/packages/compiler-sfc/src/templateUtils.ts @@ -30,7 +30,7 @@ export function parseUrl(url: string): UrlWithStringQuery { /** * vuejs/component-compiler-utils#22 Support uri fragment in transformed require - * @param urlString an url as a string + * @param urlString - an url as a string */ function parseUriParts(urlString: string): UrlWithStringQuery { // A TypeError is thrown if urlString is not a string diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index 83f9d4c8939..b24484c9e62 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -97,8 +97,8 @@ export class ComputedRefImpl { * console.log(count.value) // 0 * ``` * - * @param getter Function that produces the next value. - * @param debugOptions For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}. + * @param getter - Function that produces the next value. + * @param debugOptions - For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}. * @see {@link https://vuejs.org/api/reactivity-core.html#computed} */ export function computed( diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 1dd2fb6b017..d4a34edfef4 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -173,8 +173,8 @@ export interface ReactiveEffectRunner { * The given function will be run once immediately. Every time any reactive * property that's accessed within it gets updated, the function will run again. * - * @param fn The function that will track reactive updates. - * @param options Allows to control the effect's behaviour. + * @param fn - The function that will track reactive updates. + * @param options - Allows to control the effect's behaviour. * @returns A runner that can be used to control the effect after creation. */ export function effect( @@ -201,7 +201,7 @@ export function effect( /** * Stops the effect associated with the given runner. * - * @param runner Association with the effect to stop tracking. + * @param runner - Association with the effect to stop tracking. */ export function stop(runner: ReactiveEffectRunner) { runner.effect.stop() @@ -240,9 +240,9 @@ export function resetTracking() { * This will check which effect is running at the moment and record it as dep * which records all effects that depend on the reactive property. * - * @param target Object holding the reactive property. - * @param type Defines the type of access to the reactive property. - * @param key Identifier of the reactive property to track. + * @param target - Object holding the reactive property. + * @param type - Defines the type of access to the reactive property. + * @param key - Identifier of the reactive property to track. */ export function track(target: object, type: TrackOpTypes, key: unknown) { if (shouldTrack && activeEffect) { @@ -298,9 +298,9 @@ export function trackEffects( * Finds all deps associated with the target (or a specific property) and * triggers the effects stored within. * - * @param target The reactive object. - * @param type Defines the type of the operation that needs to trigger effects. - * @param key Can be used to target a specific reactive property in the target object. + * @param target - The reactive object. + * @param type - Defines the type of the operation that needs to trigger effects. + * @param key - Can be used to target a specific reactive property in the target object. */ export function trigger( target: object, diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index 9ab52906e14..a65c48d031b 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -113,7 +113,7 @@ export class EffectScope { * disposed together. For detailed use cases of this API, please consult its * corresponding {@link https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md | RFC}. * - * @param detached Can be used to create a "detached" effect scope. + * @param detached - Can be used to create a "detached" effect scope. * @see {@link https://vuejs.org/api/reactivity-advanced.html#effectscope} */ export function effectScope(detached?: boolean) { @@ -142,7 +142,7 @@ export function getCurrentScope() { * Registers a dispose callback on the current active effect scope. The * callback will be invoked when the associated effect scope is stopped. * - * @param fn The callback function to attach to the scope's cleanup. + * @param fn - The callback function to attach to the scope's cleanup. * @see {@link https://vuejs.org/api/reactivity-advanced.html#onscopedispose} */ export function onScopeDispose(fn: () => void) { diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index bc6c723e004..b51a5027972 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -76,7 +76,7 @@ export type UnwrapNestedRefs = T extends Ref ? T : UnwrapRefSimple * const obj = reactive({ count: 0 }) * ``` * - * @param target The source object. + * @param target - The source object. * @see {@link https://vuejs.org/api/reactivity-core.html#reactive} */ export function reactive(target: T): UnwrapNestedRefs @@ -125,7 +125,7 @@ export type ShallowReactive = T & { [ShallowReactiveMarker]?: true } * state.nested.bar++ * ``` * - * @param target The source object. + * @param target - The source object. * @see {@link https://vuejs.org/api/reactivity-advanced.html#shallowreactive} */ export function shallowReactive( @@ -190,7 +190,7 @@ export type DeepReadonly = T extends Builtin * copy.count++ // warning! * ``` * - * @param target The source object. + * @param target - The source object. * @see {@link https://vuejs.org/api/reactivity-core.html#readonly} */ export function readonly( @@ -232,7 +232,7 @@ export function readonly( * state.nested.bar++ * ``` * - * @param target The source object. + * @param target - The source object. * @see {@link https://vuejs.org/api/reactivity-advanced.html#shallowreadonly} */ export function shallowReadonly(target: T): Readonly { @@ -299,7 +299,7 @@ function createReactiveObject( * isReactive(shallowReactive({})) // => true * ``` * - * @param value The value to check. + * @param value - The value to check. * @see {@link https://vuejs.org/api/reactivity-utilities.html#isreactive} */ export function isReactive(value: unknown): boolean { @@ -317,7 +317,7 @@ export function isReactive(value: unknown): boolean { * The proxies created by {@link readonly()} and {@link shallowReadonly()} are * both considered readonly, as is a computed ref without a set function. * - * @param value The value to check. + * @param value - The value to check. * @see {@link https://vuejs.org/api/reactivity-utilities.html#isreadonly} */ export function isReadonly(value: unknown): boolean { @@ -332,7 +332,7 @@ export function isShallow(value: unknown): boolean { * Checks if an object is a proxy created by {@link reactive}, * {@link readonly}, {@link shallowReactive} or {@link shallowReadonly()}. * - * @param value The value to check. + * @param value - The value to check. * @see {@link https://vuejs.org/api/reactivity-utilities.html#isproxy} */ export function isProxy(value: unknown): boolean { @@ -359,7 +359,7 @@ export function isProxy(value: unknown): boolean { * console.log(toRaw(reactiveFoo) === foo) // true * ``` * - * @param observed The object for which the "raw" value is requested. + * @param observed - The object for which the "raw" value is requested. * @see {@link https://vuejs.org/api/reactivity-advanced.html#toraw} */ export function toRaw(observed: T): T { @@ -388,7 +388,7 @@ export type Raw = T & { [RawSymbol]?: true } * deep reactive/readonly conversion and embed raw, non-proxied objects in your * state graph. * - * @param value The object to be marked as "raw". + * @param value - The object to be marked as "raw". * @see {@link https://vuejs.org/api/reactivity-advanced.html#markraw} */ export function markRaw(value: T): Raw { @@ -401,7 +401,7 @@ export function markRaw(value: T): Raw { * * If the given value is not an object, the original value itself is returned. * - * @param value The value for which a reactive proxy shall be created. + * @param value - The value for which a reactive proxy shall be created. */ export const toReactive = (value: T): T => isObject(value) ? reactive(value) : value @@ -411,7 +411,7 @@ export const toReactive = (value: T): T => * * If the given value is not an object, the original value itself is returned. * - * @param value The value for which a readonly proxy shall be created. + * @param value - The value for which a readonly proxy shall be created. */ export const toReadonly = (value: T): T => isObject(value) ? readonly(value as Record) : value diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 33db625dcf0..85a19802d4f 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -72,7 +72,7 @@ export function triggerRefValue(ref: RefBase, newVal?: any) { /** * Checks if a value is a ref object. * - * @param r The value to inspect. + * @param r - The value to inspect. * @see {@link https://vuejs.org/api/reactivity-utilities.html#isref} */ export function isRef(r: Ref | unknown): r is Ref @@ -84,7 +84,7 @@ export function isRef(r: any): r is Ref { * Takes an inner value and returns a reactive and mutable ref object, which * has a single property `.value` that points to the inner value. * - * @param value The object to wrap in the ref. + * @param value - The object to wrap in the ref. * @see {@link https://vuejs.org/api/reactivity-core.html#ref} */ export function ref( @@ -114,7 +114,7 @@ export type ShallowRef = Ref & { [ShallowRefMarker]?: true } * state.value = { count: 2 } * ``` * - * @param value The "inner value" for the shallow ref. + * @param value - The "inner value" for the shallow ref. * @see {@link https://vuejs.org/api/reactivity-advanced.html#shallowref} */ export function shallowRef( @@ -184,7 +184,7 @@ class RefImpl { * triggerRef(shallow) * ``` * - * @param ref The ref whose tied effects shall be executed. + * @param ref - The ref whose tied effects shall be executed. * @see {@link https://vuejs.org/api/reactivity-advanced.html#triggerref} */ export function triggerRef(ref: Ref) { @@ -204,7 +204,7 @@ export function triggerRef(ref: Ref) { * } * ``` * - * @param ref Ref or plain value to be converted into the plain value. + * @param ref - Ref or plain value to be converted into the plain value. * @see {@link https://vuejs.org/api/reactivity-utilities.html#unref} */ export function unref(ref: T | Ref): T { @@ -231,7 +231,7 @@ const shallowUnwrapHandlers: ProxyHandler = { * reactive proxy is created. Direct child properties that are refs are properly * handled, as well. * - * @param objectWithRefs Either an already-reactive object or a simple object + * @param objectWithRefs - Either an already-reactive object or a simple object * that contains refs. */ export function proxyRefs( @@ -280,7 +280,7 @@ class CustomRefImpl { * Creates a customized ref with explicit control over its dependency tracking * and updates triggering. * - * @param factory The function that receives the `track` and `trigger` callbacks. + * @param factory - The function that receives the `track` and `trigger` callbacks. * @see {@link https://vuejs.org/api/reactivity-advanced.html#customref} */ export function customRef(factory: CustomRefFactory): Ref { @@ -296,7 +296,7 @@ export type ToRefs = { * resulting object is a ref pointing to the corresponding property of the * original object. Each individual ref is created using {@link toRef()}. * - * @param object Reactive object to be made into an object of linked refs. + * @param object - Reactive object to be made into an object of linked refs. * @see {@link https://vuejs.org/api/reactivity-utilities.html#torefs} */ export function toRefs(object: T): ToRefs { @@ -358,8 +358,8 @@ export type ToRef = IfAny, [T] extends [Ref] ? T : Ref> * console.log(fooRef.value) // 3 * ``` * - * @param object The reactive object containing the desired property. - * @param key Name of the property in the reactive object. + * @param object - The reactive object containing the desired property. + * @param key - Name of the property in the reactive object. * @see {@link https://vuejs.org/api/reactivity-utilities.html#toref} */ export function toRef(