new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Vue · API reference · all subjects

reactivity-api/advanced

27 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

shallowRef() signature and interface

shallowRef creates a shallow version of a ref. Type signature: function shallowRef<T>(value: T): ShallowRef<T>. The ShallowRef<T> interface has a single property: value: T.

shallowRef() behavior: inner value not deeply reactive

Unlike ref(), the inner value of a shallow ref is stored and exposed as-is and will not be made deeply reactive. Only the .value access is reactive. Mutations to nested properties do not trigger changes, but assigning a new value to .value does trigger changes.

shallowRef() use cases

shallowRef() is typically used for performance optimizations of large data structures, or integration with external state management systems.

triggerRef() signature

triggerRef forces trigger effects that depend on a shallow ref. Type signature: function triggerRef(ref: ShallowRef): void. This is typically used after making deep mutations to the inner value of a shallow ref.

customRef() signature and factory function

customRef creates a customized ref with explicit control over dependency tracking and updates triggering. Type signature: function customRef<T>(factory: CustomRefFactory<T>): Ref<T>. The CustomRefFactory<T> type is: type CustomRefFactory<T> = (track: () => void, trigger: () => void) => { get: () => T; set: (value: T) => void }. The factory function receives track and trigger functions as arguments and returns an object with get and set methods.

customRef() implementation pattern

In general, track() should be called inside get(), and trigger() should be called inside set(). However, you have full control over when they should be called, or whether they should be called at all.

customRef() debounced example

import { customRef } from 'vue' export 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) } } }) } Usage in component: <script setup> import { useDebouncedRef } from './debouncedRef' const text = useDebouncedRef('hello') </script> <template> <input v-model="text" /> </template> This example shows a debounced ref that only updates the value after a certain timeout after the latest set call.

customRef() pitfall: new objects from getter

When using customRef, be cautious about the return value of its getter, particularly when generating new object datatypes each time the getter is run. If a parent component's render function is triggered by different reactive state, during rerender the customRef value is reevaluated, potentially returning a new object as a prop to a child component. Since the new object differs from the last value, reactive dependencies are triggered in the child, but the parent's reactive dependencies do not run because the customRef setter was not called.

shallowReactive() signature

shallowReactive creates a shallow version of reactive. Type signature: function shallowReactive<T extends object>(target: T): T.

shallowReactive() behavior: only root-level reactive

Unlike reactive(), there is no deep conversion in shallowReactive(): only root-level properties are reactive. Property values are stored and exposed as-is. Properties with ref values will not be automatically unwrapped. Nested objects are not made reactive.

shallowReadonly() signature

shallowReadonly creates a shallow version of readonly. Type signature: function shallowReadonly<T extends object>(target: T): Readonly<T>.

shallowReadonly() behavior: only root-level readonly

Unlike readonly(), there is no deep conversion in shallowReadonly(): only root-level properties are made readonly. Property values are stored and exposed as-is. Properties with ref values will not be automatically unwrapped. Nested objects remain mutable.

shallowReadonly() usage caution

Shallow data structures should only be used for root level state in a component. Avoid nesting shallowReadonly inside a deep reactive object as it creates a tree with inconsistent reactivity behavior which can be difficult to understand and debug.

toRaw() signature and purpose

toRaw returns the raw, original object of a Vue-created proxy. Type signature: function toRaw<T>(proxy: T): T. toRaw can return the original object from proxies created by reactive(), readonly(), shallowReactive(), or shallowReadonly().

toRaw() use cases

toRaw 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.

markRaw() signature and purpose

markRaw marks an object so that it will never be converted to a proxy. Type signature: function markRaw<T extends object>(value: T): T. markRaw returns the object itself.

markRaw() behavior with nested objects

markRaw marks an object to prevent proxy conversion. When a marked raw object is nested inside a reactive object, accessing it again returns the proxied version. This occurs because markRaw only prevents conversion at the root level - if nested properties are not individually marked as raw, they can still be proxied.

markRaw() use cases

markRaw and shallow APIs such as shallowReactive allow selective opt-out of default deep reactive/readonly conversion. Some values 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.

markRaw() identity hazard pitfall

markRaw and shallow APIs have an advanced pitfall: the raw opt-out is only at the root level. 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 creates identity hazards - performing an operation that relies on object identity but using both the raw and the proxied version of the same object will fail. For example, a marked raw object with nested properties will have those nested properties proxied when placed in a reactive object, causing identity comparison to fail.

effectScope() signature and interface

effectScope creates an effect scope object which can capture reactive effects (computed and watchers) created within it. Type signature: function effectScope(detached?: boolean): EffectScope. The EffectScope interface has: run<T>(fn: () => T): T | undefined (returns undefined if scope is inactive) and stop(): void.

effectScope() purpose

effectScope allows capturing reactive effects (computed and watchers) created within it so that these effects can be disposed together.

getCurrentScope() signature

getCurrentScope returns the current active effect scope if there is one. Type signature: function getCurrentScope(): EffectScope | undefined.

onScopeDispose() signature and purpose

onScopeDispose registers a dispose callback on the current active effect scope. Type signature: function onScopeDispose(fn: () => void, failSilently?: boolean): void. The callback will be invoked when the associated effect scope is stopped.

onScopeDispose() as non-component-coupled lifecycle hook

onScopeDispose can be used as a non-component-coupled replacement of onUnmounted in reusable composition functions, since each Vue component's setup() function is invoked in an effect scope.

onScopeDispose() error handling

A warning will be thrown if onScopeDispose is called without an active effect scope. In Vue 3.5+, this warning can be suppressed by passing true as the second argument (failSilently parameter).

shallowRef() for external state management integration

shallowRef() is designed for integrating with external state management systems. A shallow ref is only reactive when its .value property is accessed. The inner value is left intact. When external state changes, replace the ref value to trigger updates.

Shallow refs opt-out deep reactivity

For shallow refs, only .value access is tracked for reactivity. Shallow refs can be used for optimizing performance by avoiding the observation cost of large objects, or in cases where the inner state is managed by an external library.

Give your agent this brain