close #4832
This commit is contained in:
parent
5261085113
commit
c346af2b6a
|
@ -30,7 +30,7 @@ export function parseUrl(url: string): UrlWithStringQuery {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vuejs/component-compiler-utils#22 Support uri fragment in transformed require
|
* 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 {
|
function parseUriParts(urlString: string): UrlWithStringQuery {
|
||||||
// A TypeError is thrown if urlString is not a string
|
// A TypeError is thrown if urlString is not a string
|
||||||
|
|
|
@ -68,6 +68,39 @@ export class ComputedRefImpl<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
*
|
||||||
|
* console.log(plusOne.value) // 2
|
||||||
|
* plusOne.value++ // error
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* // Creating a writable computed ref:
|
||||||
|
* 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
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @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<T>(
|
export function computed<T>(
|
||||||
getter: ComputedGetter<T>,
|
getter: ComputedGetter<T>,
|
||||||
debugOptions?: DebuggerOptions
|
debugOptions?: DebuggerOptions
|
||||||
|
|
|
@ -167,6 +167,16 @@ export interface ReactiveEffectRunner<T = any> {
|
||||||
effect: ReactiveEffect
|
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 after creation.
|
||||||
|
*/
|
||||||
export function effect<T = any>(
|
export function effect<T = any>(
|
||||||
fn: () => T,
|
fn: () => T,
|
||||||
options?: ReactiveEffectOptions
|
options?: ReactiveEffectOptions
|
||||||
|
@ -188,6 +198,11 @@ export function effect<T = any>(
|
||||||
return runner
|
return runner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the effect associated with the given runner.
|
||||||
|
*
|
||||||
|
* @param runner - Association with the effect to stop tracking.
|
||||||
|
*/
|
||||||
export function stop(runner: ReactiveEffectRunner) {
|
export function stop(runner: ReactiveEffectRunner) {
|
||||||
runner.effect.stop()
|
runner.effect.stop()
|
||||||
}
|
}
|
||||||
|
@ -195,21 +210,40 @@ export function stop(runner: ReactiveEffectRunner) {
|
||||||
export let shouldTrack = true
|
export let shouldTrack = true
|
||||||
const trackStack: boolean[] = []
|
const trackStack: boolean[] = []
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporarily pauses tracking.
|
||||||
|
*/
|
||||||
export function pauseTracking() {
|
export function pauseTracking() {
|
||||||
trackStack.push(shouldTrack)
|
trackStack.push(shouldTrack)
|
||||||
shouldTrack = false
|
shouldTrack = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-enables effect tracking (if it was paused).
|
||||||
|
*/
|
||||||
export function enableTracking() {
|
export function enableTracking() {
|
||||||
trackStack.push(shouldTrack)
|
trackStack.push(shouldTrack)
|
||||||
shouldTrack = true
|
shouldTrack = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the previous global effect tracking state.
|
||||||
|
*/
|
||||||
export function resetTracking() {
|
export function resetTracking() {
|
||||||
const last = trackStack.pop()
|
const last = trackStack.pop()
|
||||||
shouldTrack = last === undefined ? true : last
|
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 to track.
|
||||||
|
*/
|
||||||
export function track(target: object, type: TrackOpTypes, key: unknown) {
|
export function track(target: object, type: TrackOpTypes, key: unknown) {
|
||||||
if (shouldTrack && activeEffect) {
|
if (shouldTrack && activeEffect) {
|
||||||
let depsMap = targetMap.get(target)
|
let depsMap = targetMap.get(target)
|
||||||
|
@ -260,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(
|
export function trigger(
|
||||||
target: object,
|
target: object,
|
||||||
type: TriggerOpTypes,
|
type: TriggerOpTypes,
|
||||||
|
|
|
@ -107,6 +107,15 @@ 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 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.
|
||||||
|
* @see {@link https://vuejs.org/api/reactivity-advanced.html#effectscope}
|
||||||
|
*/
|
||||||
export function effectScope(detached?: boolean) {
|
export function effectScope(detached?: boolean) {
|
||||||
return new EffectScope(detached)
|
return new EffectScope(detached)
|
||||||
}
|
}
|
||||||
|
@ -120,10 +129,22 @@ export function recordEffectScope(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current active effect scope if there is one.
|
||||||
|
*
|
||||||
|
* @see {@link https://vuejs.org/api/reactivity-advanced.html#getcurrentscope}
|
||||||
|
*/
|
||||||
export function getCurrentScope() {
|
export function getCurrentScope() {
|
||||||
return activeEffectScope
|
return activeEffectScope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
export function onScopeDispose(fn: () => void) {
|
||||||
if (activeEffectScope) {
|
if (activeEffectScope) {
|
||||||
activeEffectScope.cleanups.push(fn)
|
activeEffectScope.cleanups.push(fn)
|
||||||
|
|
|
@ -65,26 +65,19 @@ function getTargetType(value: Target) {
|
||||||
export type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRefSimple<T>
|
export type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRefSimple<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a reactive copy of the original object.
|
* Returns a reactive proxy of the object.
|
||||||
*
|
*
|
||||||
* The reactive conversion is "deep"—it affects all nested properties. In the
|
* The reactive conversion is "deep": it affects all nested properties. A
|
||||||
* ES2015 Proxy based implementation, the returned proxy is **not** equal to the
|
* reactive object also deeply unwraps any properties that are refs while
|
||||||
* original object. It is recommended to work exclusively with the reactive
|
* maintaining reactivity.
|
||||||
* 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:
|
|
||||||
*
|
*
|
||||||
|
* @example
|
||||||
* ```js
|
* ```js
|
||||||
* const count = ref(0)
|
* const obj = reactive({ count: 0 })
|
||||||
* const obj = reactive({
|
|
||||||
* count
|
|
||||||
* })
|
|
||||||
*
|
|
||||||
* obj.count++
|
|
||||||
* obj.count // -> 1
|
|
||||||
* count.value // -> 1
|
|
||||||
* ```
|
* ```
|
||||||
|
*
|
||||||
|
* @param target - The source object.
|
||||||
|
* @see {@link https://vuejs.org/api/reactivity-core.html#reactive}
|
||||||
*/
|
*/
|
||||||
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
|
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
|
||||||
export function reactive(target: object) {
|
export function reactive(target: object) {
|
||||||
|
@ -106,9 +99,34 @@ export declare const ShallowReactiveMarker: unique symbol
|
||||||
export type ShallowReactive<T> = T & { [ShallowReactiveMarker]?: true }
|
export type ShallowReactive<T> = T & { [ShallowReactiveMarker]?: true }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a shallowly-reactive copy of the original object, where only the root
|
* Shallow version of {@link reactive()}.
|
||||||
* level properties are reactive. It also does not auto-unwrap refs (even at the
|
*
|
||||||
* root level).
|
* 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 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
|
||||||
|
*
|
||||||
|
* // NOT reactive
|
||||||
|
* state.nested.bar++
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param target - The source object.
|
||||||
|
* @see {@link https://vuejs.org/api/reactivity-advanced.html#shallowreactive}
|
||||||
*/
|
*/
|
||||||
export function shallowReactive<T extends object>(
|
export function shallowReactive<T extends object>(
|
||||||
target: T
|
target: T
|
||||||
|
@ -147,8 +165,33 @@ export type DeepReadonly<T> = T extends Builtin
|
||||||
: Readonly<T>
|
: Readonly<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a readonly copy of the original object. Note the returned copy is not
|
* Takes an object (reactive or plain) or a ref and returns a readonly proxy to
|
||||||
* made reactive, but `readonly` can be called on an already reactive object.
|
* the original.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* 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!
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param target - The source object.
|
||||||
|
* @see {@link https://vuejs.org/api/reactivity-core.html#readonly}
|
||||||
*/
|
*/
|
||||||
export function readonly<T extends object>(
|
export function readonly<T extends object>(
|
||||||
target: T
|
target: T
|
||||||
|
@ -163,10 +206,34 @@ export function readonly<T extends object>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a reactive-copy of the original object, where only the root level
|
* Shallow version of {@link readonly()}.
|
||||||
* properties are readonly, and does NOT unwrap refs nor recursively convert
|
*
|
||||||
* returned properties.
|
* Unlike {@link readonly()}, there is no deep conversion: only root-level
|
||||||
* This is used for creating the props proxy object for stateful components.
|
* 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
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* // works
|
||||||
|
* state.nested.bar++
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param target - The source object.
|
||||||
|
* @see {@link https://vuejs.org/api/reactivity-advanced.html#shallowreadonly}
|
||||||
*/
|
*/
|
||||||
export function shallowReadonly<T extends object>(target: T): Readonly<T> {
|
export function shallowReadonly<T extends object>(target: T): Readonly<T> {
|
||||||
return createReactiveObject(
|
return createReactiveObject(
|
||||||
|
@ -217,6 +284,24 @@ function createReactiveObject(
|
||||||
return proxy
|
return proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an object is a proxy created by {@link reactive()} or
|
||||||
|
* {@link shallowReactive()} (or {@link ref()} in some cases).
|
||||||
|
*
|
||||||
|
* @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 {
|
export function isReactive(value: unknown): boolean {
|
||||||
if (isReadonly(value)) {
|
if (isReadonly(value)) {
|
||||||
return isReactive((value as Target)[ReactiveFlags.RAW])
|
return isReactive((value as Target)[ReactiveFlags.RAW])
|
||||||
|
@ -224,6 +309,17 @@ export function isReactive(value: unknown): boolean {
|
||||||
return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE])
|
return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
export function isReadonly(value: unknown): boolean {
|
||||||
return !!(value && (value as Target)[ReactiveFlags.IS_READONLY])
|
return !!(value && (value as Target)[ReactiveFlags.IS_READONLY])
|
||||||
}
|
}
|
||||||
|
@ -232,10 +328,40 @@ export function isShallow(value: unknown): boolean {
|
||||||
return !!(value && (value as Target)[ReactiveFlags.IS_SHALLOW])
|
return !!(value && (value as Target)[ReactiveFlags.IS_SHALLOW])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
export function isProxy(value: unknown): boolean {
|
||||||
return isReactive(value) || isReadonly(value)
|
return isReactive(value) || isReadonly(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
* @see {@link https://vuejs.org/api/reactivity-advanced.html#toraw}
|
||||||
|
*/
|
||||||
export function toRaw<T>(observed: T): T {
|
export function toRaw<T>(observed: T): T {
|
||||||
const raw = observed && (observed as Target)[ReactiveFlags.RAW]
|
const raw = observed && (observed as Target)[ReactiveFlags.RAW]
|
||||||
return raw ? toRaw(raw) : observed
|
return raw ? toRaw(raw) : observed
|
||||||
|
@ -243,13 +369,49 @@ export function toRaw<T>(observed: T): T {
|
||||||
|
|
||||||
export type Raw<T> = T & { [RawSymbol]?: true }
|
export type Raw<T> = T & { [RawSymbol]?: true }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks an object so that it will never be converted to a proxy. Returns the
|
||||||
|
* object itself.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```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()` 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<T extends object>(value: T): Raw<T> {
|
export function markRaw<T extends object>(value: T): Raw<T> {
|
||||||
def(value, ReactiveFlags.SKIP, true)
|
def(value, ReactiveFlags.SKIP, true)
|
||||||
return value
|
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.
|
||||||
|
*
|
||||||
|
* @param value - The value for which a reactive proxy shall be created.
|
||||||
|
*/
|
||||||
export const toReactive = <T extends unknown>(value: T): T =>
|
export const toReactive = <T extends unknown>(value: T): T =>
|
||||||
isObject(value) ? reactive(value) : value
|
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.
|
||||||
|
*
|
||||||
|
* @param value - The value for which a readonly proxy shall be created.
|
||||||
|
*/
|
||||||
export const toReadonly = <T extends unknown>(value: T): T =>
|
export const toReadonly = <T extends unknown>(value: T): T =>
|
||||||
isObject(value) ? readonly(value as Record<any, any>) : value
|
isObject(value) ? readonly(value as Record<any, any>) : value
|
||||||
|
|
|
@ -69,11 +69,24 @@ export function triggerRefValue(ref: RefBase<any>, 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<T>(r: Ref<T> | unknown): r is Ref<T>
|
export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>
|
||||||
export function isRef(r: any): r is Ref {
|
export function isRef(r: any): r is Ref {
|
||||||
return !!(r && r.__v_isRef === true)
|
return !!(r && r.__v_isRef === true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<T extends object>(
|
export function ref<T extends object>(
|
||||||
value: T
|
value: T
|
||||||
): [T] extends [Ref] ? T : Ref<UnwrapRef<T>>
|
): [T] extends [Ref] ? T : Ref<UnwrapRef<T>>
|
||||||
|
@ -87,6 +100,23 @@ declare const ShallowRefMarker: unique symbol
|
||||||
|
|
||||||
export type ShallowRef<T = any> = Ref<T> & { [ShallowRefMarker]?: true }
|
export type ShallowRef<T = any> = Ref<T> & { [ShallowRefMarker]?: true }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shallow version of {@link ref()}.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js
|
||||||
|
* const state = shallowRef({ count: 1 })
|
||||||
|
*
|
||||||
|
* // 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<T extends object>(
|
export function shallowRef<T extends object>(
|
||||||
value: T
|
value: T
|
||||||
): T extends Ref ? T : ShallowRef<T>
|
): T extends Ref ? T : ShallowRef<T>
|
||||||
|
@ -132,10 +162,51 @@ class RefImpl<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* 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)
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @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) {
|
export function triggerRef(ref: Ref) {
|
||||||
triggerRefValue(ref, __DEV__ ? ref.value : void 0)
|
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`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js
|
||||||
|
* function useFoo(x: number | Ref<number>) {
|
||||||
|
* 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<T>(ref: T | Ref<T>): T {
|
export function unref<T>(ref: T | Ref<T>): T {
|
||||||
return isRef(ref) ? (ref.value as any) : ref
|
return isRef(ref) ? (ref.value as any) : ref
|
||||||
}
|
}
|
||||||
|
@ -153,6 +224,16 @@ const shallowUnwrapHandlers: ProxyHandler<any> = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<T extends object>(
|
export function proxyRefs<T extends object>(
|
||||||
objectWithRefs: T
|
objectWithRefs: T
|
||||||
): ShallowUnwrapRef<T> {
|
): ShallowUnwrapRef<T> {
|
||||||
|
@ -195,6 +276,13 @@ class CustomRefImpl<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @see {@link https://vuejs.org/api/reactivity-advanced.html#customref}
|
||||||
|
*/
|
||||||
export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
|
export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
|
||||||
return new CustomRefImpl(factory) as any
|
return new CustomRefImpl(factory) as any
|
||||||
}
|
}
|
||||||
|
@ -202,6 +290,15 @@ export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
|
||||||
export type ToRefs<T = any> = {
|
export type ToRefs<T = any> = {
|
||||||
[K in keyof T]: ToRef<T[K]>
|
[K in keyof T]: ToRef<T[K]>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {@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<T extends object>(object: T): ToRefs<T> {
|
export function toRefs<T extends object>(object: T): ToRefs<T> {
|
||||||
if (__DEV__ && !isProxy(object)) {
|
if (__DEV__ && !isProxy(object)) {
|
||||||
console.warn(`toRefs() expects a reactive object but received a plain one.`)
|
console.warn(`toRefs() expects a reactive object but received a plain one.`)
|
||||||
|
@ -238,17 +335,42 @@ class ObjectRefImpl<T extends object, K extends keyof T> {
|
||||||
|
|
||||||
export type ToRef<T> = IfAny<T, Ref<T>, [T] extends [Ref] ? T : Ref<T>>
|
export type ToRef<T> = IfAny<T, Ref<T>, [T] extends [Ref] ? T : Ref<T>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* const state = reactive({
|
||||||
|
* foo: 1,
|
||||||
|
* bar: 2
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @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<T extends object, K extends keyof T>(
|
export function toRef<T extends object, K extends keyof T>(
|
||||||
object: T,
|
object: T,
|
||||||
key: K
|
key: K
|
||||||
): ToRef<T[K]>
|
): ToRef<T[K]>
|
||||||
|
|
||||||
export function toRef<T extends object, K extends keyof T>(
|
export function toRef<T extends object, K extends keyof T>(
|
||||||
object: T,
|
object: T,
|
||||||
key: K,
|
key: K,
|
||||||
defaultValue: T[K]
|
defaultValue: T[K]
|
||||||
): ToRef<Exclude<T[K], undefined>>
|
): ToRef<Exclude<T[K], undefined>>
|
||||||
|
|
||||||
export function toRef<T extends object, K extends keyof T>(
|
export function toRef<T extends object, K extends keyof T>(
|
||||||
object: T,
|
object: T,
|
||||||
key: K,
|
key: K,
|
||||||
|
|
Loading…
Reference in New Issue