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 · all subjects

reactivity: advanced

26 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 behavior

shallowRef creates a shallow version of ref. Its type signature is: function shallowRef<T>(value: T): ShallowRef<T> where ShallowRef<T> has a value property of type T. Unlike ref(), the inner value is stored and exposed as-is without deep reactivity. Only the .value access is reactive, not mutations to nested properties.

shallowRef example: what triggers change

When using shallowRef, mutating nested properties directly (state.value.count = 2) does NOT trigger change. Only reassigning the entire .value property (state.value = { count: 2 }) triggers change.

triggerRef() signature and purpose

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

triggerRef example

Example: const shallow = shallowRef({ greet: 'Hello, world' }); watchEffect(() => { console.log(shallow.value.greet) }); shallow.value.greet = 'Hello, universe'; // Won't trigger the effect because ref is shallow; triggerRef(shallow); // Now it logs 'Hello, universe'

customRef() signature and factory function

customRef creates a customized ref with explicit control over dependency tracking and updates. Signature: function customRef<T>(factory: CustomRefFactory<T>): Ref<T> where CustomRefFactory<T> = (track: () => void, trigger: () => void) => { get: () => T, set: (value: T) => void }. The factory receives track and trigger functions and must return an object with get and set methods.

customRef get and set methods: when to call track and trigger

In customRef, track() should generally be called inside get(), and trigger() should be called inside set(). However, you have full control over when and whether they should be called.

customRef example: debounced ref

Example of a debounced ref that only updates after a timeout: 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) } } }) }

customRef warning: getter return value and props

When using customRef, be cautious about the return value of its getter, especially when generating new object datatypes each time. If passed as a prop to a child component, the new object on each reevaluation can cause identity differences and unexpected reactive behavior in the child component while parent dependencies may not trigger.

shallowReactive() signature and behavior

shallowReactive has the signature: function shallowReactive<T extends object>(target: T): T. It is a shallow version of reactive() with no deep conversion - only root-level properties are reactive. Property values are stored as-is, and properties with ref values will NOT be automatically unwrapped.

shallowReactive example: nested properties not reactive

Example: const state = shallowReactive({ foo: 1, nested: { bar: 2 } }); state.foo++; // reactive; isReactive(state.nested) // false; state.nested.bar++; // NOT reactive

shallowReactive usage caution

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

shallowReadonly() signature and behavior

shallowReadonly has the signature: function shallowReadonly<T extends object>(target: T): Readonly<T>. It is a shallow version of readonly() with no deep conversion - only root-level properties are made readonly. Property values are stored as-is, and properties with ref values will NOT be automatically unwrapped.

shallowReadonly example: nested properties mutable

Example: const state = shallowReadonly({ foo: 1, nested: { bar: 2 } }); state.foo++; // fails; isReadonly(state.nested) // false; state.nested.bar++; // works

toRaw() signature and purpose

toRaw has the signature: function toRaw<T>(proxy: T): T. It returns the raw, original object of a Vue-created proxy, working with proxies created by reactive(), readonly(), shallowReactive(), or shallowReadonly().

toRaw() use case and caution

toRaw is an escape hatch 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 and should be used with caution.

toRaw example

Example: const foo = {}; const reactiveFoo = reactive(foo); console.log(toRaw(reactiveFoo) === foo) // true

markRaw() signature and purpose

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

markRaw example: preventing proxy conversion

Example: const foo = markRaw({}); console.log(isReactive(reactive(foo))) // false. Also works when nested: const bar = reactive({ foo }); console.log(isReactive(bar.foo)) // false

markRaw identity hazards pitfall

markRaw and shallow APIs allow opting out of deep conversion, but the raw opt-out is only at the root level. If you set a nested non-marked raw object into a reactive object and access it again, you get the proxied version back. This can lead to identity hazards where the same object exists as both raw and proxied versions. Example: const foo = markRaw({ nested: {} }); const bar = reactive({ nested: foo.nested }); console.log(foo.nested === bar.nested) // false

markRaw use cases

markRaw should be used when: some values should not be made reactive (complex 3rd party class instances, Vue component objects), or skipping proxy conversion provides performance improvements when rendering large lists with immutable data sources.

effectScope() signature and interface

effectScope has the signature: function effectScope(detached?: boolean): EffectScope where EffectScope interface is: { run<T>(fn: () => T): T | undefined; stop(): void }. It creates an effect scope object that captures reactive effects (computed and watchers) created within it so they can be disposed together.

effectScope example: capturing and disposing effects

Example: const scope = effectScope(); scope.run(() => { const doubled = computed(() => counter.value * 2); watch(doubled, () => console.log(doubled.value)); watchEffect(() => console.log('Count: ', doubled.value)); }); scope.stop(); // disposes all effects in the scope

getCurrentScope() signature and purpose

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

onScopeDispose() signature and purpose

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

onScopeDispose() use as non-component-coupled replacement for onUnmounted

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

onScopeDispose() warning behavior

A warning is 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).

Give your agent this brain