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/core

84 notes in this subject, read out of this brain and free to use. This is page 2 of 2.

Refs are similar to 'signals' in other frameworks

Vue refs are fundamentally the same kind of reactivity primitive as 'signals' in other frameworks (Solid, Angular, Preact, Qwik). Signals are value containers that provide dependency tracking on access and side-effect triggering on mutation. This paradigm dates back to Knockout observables and Meteor Tracker.

How Options API relates to Composition API reactivity

In Vue 3, the Options API is implemented on top of the Composition API. All property access on the component instance (this) triggers getter/setters for reactivity tracking. Options like watch and computed invoke their Composition API equivalents internally.

Why Vue uses Proxy for reactive() and getter/setter for ref()

Vue 2 used getter/setters exclusively due to browser support limitations. Vue 3 uses Proxies for reactive objects because they can intercept any property access. Getter/setters are used for refs as an alternative mechanism for value containers.

Limitation: destructuring reactive object properties to local variables loses reactivity

When you assign or destructure a reactive object's property to a local variable, accessing or assigning to that variable is non-reactive because it no longer triggers the get/set proxy traps on the source object. The 'disconnect' only affects the variable binding. If the variable points to a non-primitive value like an object, mutating that object is still reactive.

Reactive proxy has different identity than original object

The returned proxy from reactive() behaves just like the original object but has a different identity when compared using the === operator.

reactive() uses Proxy to intercept object property access

Vue 3 uses Proxies for reactive objects. The reactive() function wraps an object in a Proxy with get and set traps. The get trap calls track(target, key) and returns the property value. The set trap assigns the new value and calls trigger(target, key).

Ref unwrapped in text interpolation tags

A ref gets unwrapped if it is the final evaluated value of a text interpolation ({{ }} tag), so {{ object.id }} will render the unwrapped value. This is equivalent to {{ object.id.value }}.

Deep reactivity with ref

Refs make their value deeply reactive by default. A ref can hold any value type including deeply nested objects, arrays, or JavaScript built-in data structures like Map. Changes are detected even when mutating nested objects or arrays: obj.value.nested.count++ and obj.value.arr.push('baz') work as expected.

reactive() converts object deeply

reactive() converts an object deeply: nested objects are also wrapped with reactive() when accessed. It is also called by ref() internally when the ref value is an object. There is a shallowReactive() API available for opting-out of deep reactivity.

DOM updates are buffered until next tick

When reactive state is mutated, the DOM is not updated synchronously. Instead, Vue buffers DOM updates until the next tick in the update cycle to ensure each component updates only once no matter how many state changes have been made.

ref() returns same proxy for same underlying data

When a ref holds an object, non-primitive values are turned into reactive proxies via reactive() internally. Nested objects inside a ref are also reactive proxies.

Deep reactivity in Options API

In Vue with Options API, state is deeply reactive by default. Changes are detected even when you mutate nested objects or arrays: this.obj.nested.count++ and this.obj.arr.push('baz') work as expected.

Vue Proxy wraps assigned objects, original unchanged

In Vue 3, when you assign an object to a reactive property, accessing that property returns a reactive proxy of the original object, not the original itself. When you access this.someObject after assigning newObject, the value is a reactive proxy. The original object is left intact and will not be made reactive. Always access reactive state as a property of this.

ref() wraps value in object with .value property

The ref() function takes an argument and returns it wrapped within a ref object with a .value property. Accessing the ref object shows the wrapper structure: const count = ref(0) returns { value: 0 }. The actual value is accessed via count.value.

ref() automatically unwrapped in templates

Refs are automatically unwrapped when used inside templates, so you do not need to append .value when using a ref in template expressions. For example, a button can use @click="count++" directly without @click="count.value++".

Why refs use .value property

Refs use a .value property because Vue's reactivity system is based on dependency-tracking. JavaScript has no way to detect access or mutation of plain variables, but Vue can intercept get and set operations on object properties using getters and setters. The .value property gives Vue the opportunity to detect when a ref has been accessed or mutated, performing tracking in the getter and triggering in the setter.

Ref benefits for passing into functions

Unlike plain variables, refs can be passed into functions while retaining access to the latest value and the reactivity connection. This is particularly useful when refactoring complex logic into reusable code.

reactive() makes object itself reactive, not wrapped

The reactive() API makes an object itself reactive, unlike ref() which wraps the inner value in a special object. Called as const state = reactive({ count: 0 }), it directly returns a reactive version of the object without a .value wrapper.

reactive() returns Proxy of original object

The value returned from reactive() is a Proxy of the original object and is not equal to the original object. Only the proxy is reactive; mutating the original object will not trigger updates. Best practice is to exclusively use the proxied versions of state.

reactive() on same object returns same proxy

Calling reactive() on the same object always returns the same proxy. Calling reactive() on an existing proxy also returns that same proxy. This rule applies to nested objects as well; due to deep reactivity, nested objects inside a reactive object are also proxies.

reactive() limitations

reactive() has three limitations: (1) It only works for object types (objects, arrays, Map, Set) and cannot hold primitive types like string, number or boolean. (2) Cannot replace entire object because Vue's reactivity tracking works over property access and the reactivity connection is lost if you reassign the reference. (3) Not destructure-friendly: destructuring a reactive object's primitive property into local variables or passing that property into a function loses the reactivity connection.

ref automatically unwrapped as reactive object property

A ref is automatically unwrapped when accessed or mutated as a property of a reactive object. It behaves like a normal property: const count = ref(0); const state = reactive({ count }); console.log(state.count) returns 0 directly. If a new ref is assigned to a property linked to an existing ref, it replaces the old ref and the original ref becomes disconnected.

ref NOT unwrapped in arrays and collections

Unlike reactive objects, there is no unwrapping performed when a ref is accessed as an element of a reactive array or a native collection type like Map. You must use .value: const books = reactive([ref('Vue 3 Guide')]); console.log(books[0].value); and const map = reactive(new Map([['count', ref(0)]])); console.log(map.get('count').value);

Ref unwrapping in templates only for top-level properties

Ref unwrapping in templates only applies if the ref is a top-level property in the template render context. For example, {{ count + 1 }} works as expected for a top-level count ref, but {{ object.id + 1 }} does NOT work if object is top-level but id is nested inside it. To fix this, destructure id into a top-level property.

Give your agent this brain