Fundamentals of Reactivity | vue.js (2023)

API preference

This page and many other chapters later in the guide contain different content for the Options API and the Composition API. Your current preference isOptions APIComposition API🇧🇷 You can toggle between API styles using the "API Preferences" options at the top of the left sidebar.

reactive status statement#

With the Options API, we use theDiceOption to declare the reactive state of a component. The option value must be a function that returns an object. Vue will call the function when creating a new component instance and will wrap the returned object in its reactivity system. Any top-level properties of this object are rendered in the component instance (That isin methods and lifecycle hooks):


export failure { Dice() { give back {tell: 1 } }, // `mounted` is a lifecycle hook which we'll explain later mounted() { // `this` refers to the component instance. console.Begin session(That is.tell)// => 1 // data can also be modified That is.tell = 2 }}

try it on the playground

These instance properties are only added when the instance is first created, so you must ensure that they are all present in the object returned by the instance.DiceOccupation. When necessary, usenull,Undefinedor some other placeholder value for properties where the desired value is not yet available.

It is possible to add a new property directlyThat iswithout including it inDice🇧🇷 However, properties added this way will not be able to trigger reactive updates.

Vue uses aPSprefix when exposing your own built-in APIs through the component instance. The prefix is ​​also reserved_by internal properties. You should avoid using names for the top levelDiceproperties starting with any of these characters.

Reactive proxy against the original#

In Vue 3, data becomes reactive by leveragingProxies de JavaScript🇧🇷 Users coming from Vue 2 should be aware of the following edge case:


export failure { Dice() { give back {some object: {} } }, mounted() { constant novoobjeto = {} That is.some object = novoobjeto console.Begin session(novoobjeto === That is.some object)// false }}

when you accessthis.someobjectafter assigning it, the value is a reactive proxy of the originalnovoobjeto.Unlike Vue 2, the originalnovoobjetois left untouched and will not become reactive - make sure you always access the reactive state as a property ofThat is.

We can create a reactive object or an array with thereagent()Occupation:


to import { reagent } do 'vista'constantstate= reagent({ tell: 0 })

Reactive objects areProxies de JavaScriptand behave like normal objects. The difference is that Vue can track property access and mutations of a reactive object. If you're curious about the details, we'll explain how Vue's reactivity system works atdepth reactivity- but we recommend reading it after finishing the main guide.

See too:reactive typing

To use reactive state in a component's model, declare and return it from a component's model.context()Occupation:


to import { reagent } do 'vista'export failure { // `setup` is a special hook dedicated to the composition API. context() { constant state = reagent({tell: 0 }) // expose the state to the template give back { state } }}


(Video) Fundamentals of Reactivity in Vue 3


Similarly, we can declare functions that modify the reactive state in the same scope and expose it as a method along with the state:


to import { reagent } do 'vista'export failure { context() { constant state = reagent({tell: 0 }) Occupation increment() { state.tell++ } // don't forget to expose the function too. give back { state, increment } }}

The exposed methods are typically used as event listeners:


<button@click="increment"> {{state.tell}}</button>

<script configuration> #

Manually expose state and methods viacontext()can be detailed. Fortunately, it's only needed when you're not using a build step. By using Single File Components (SFC) we can greatly simplify usage with<script configuration>:


<road map context>to import { reagent } do 'vista'constantstate= reagent({ tell: 0 })Occupation increment() { state.tell++}</road map><model> <button@click="increment"> {{state.tell}} </button></model>

try it on the playground

Top-level imports and variables declared in<script configuration>they can be used automatically in the model of the same component.

For the remainder of the guide, we will primarily use SFC+<script configuration>syntax for the Composition API code examples as it is the most common usage for Vue developers.

method declaration#

To add methods to a component instance, we use themethodsoption. This should be an object containing the desired methods:


export failure { Dice() { give back {tell: 0 } }, methods: { increment() { That is.tell++ } }, mounted() { // Methods can be called in lifecycle hooks or other methods! That is.increment() }}

Vue automatically turns on theThat isvalue formethodsso that it always refers to the component instance. This ensures that a method retains the correctThat isvalue if used as an event listener or callback. You should avoid using arrow functions when definingmethods, as this prevents Vue from binding theThat isvaleria:


export failure { methods: { increment: () => { // BAD: no 'east' access here! } }}

Like all other component instance properties, themethodsthey are accessible from the component model. Within a model they are most commonly used as event listeners:



try it on the playground

In the example above, the methodincrementwill be called when the<button>is clicked.

DOM update time#

When the reactive state changes, the DOM is automatically updated. However, it should be noted that DOM updates are not applied synchronously. Instead, Vue buffers them until the "next tick" in the update cycle to ensure that each component is only updated once, no matter how many state changes have been made.

To wait for the DOM update to complete after a state change, you can use thenextTick()Global APIs:


(Video) Stability and Reactivity | Chemistry Fundamentals

to import { nextTick } do 'vista'Occupation increment() { state.tell++ nextTick(() => { // access the updated DOM })}


to import { nextTick } do 'vista'export failure { methods: { increment() { That is.tell++ nextTick(() => { // access the updated DOM }) } }}

deep reactivity#

In Vue, state is deeply reactive by default. This means that you can expect changes to be detected even when you transform objects or nested arrays:


export failure { Dice() { give back {object: {nested: {tell: 0 },Arr:['Foo', 'bar'] } } }, methods: { mute deeply() { // these will work as expected. That is.object.nested.tell++ That is.object.Arr.Push('baz') } }}


to import { reagent } do 'vista'constantobject= reagent({ nested: { tell: 0 }, Arr:['Foo', 'bar']})Occupation mute deeply() { // these will work as expected. object.nested.tell++ object.Arr.Push('baz')}

It is also possible to explicitly createshallow reactive objectswhere reactivity is only tracked at the root level, but are generally only needed in advanced use cases.

Reactive proxy against the original#

It is important to note that the value returned byreagent()it is aAttorneyof the original object, which is not equal to the original object:


constantcru= {}constantattorney= reagent(cru)// proxy is NOT the same as the original.console.Begin session(attorney===cru)// false

Only the proxy is reactive: mutating the original object will not trigger updates. Therefore, best practice when working with Vue's reactivity system is toexclusively use proxy versions of your state.

To ensure consistent access to the proxy, callreagent()on the same object always returns the same proxy, and callingreagent()on an existing proxy also returns the same proxy:


// calling react() on the same object returns the same proxyconsole.Begin session(reagent(cru)===attorney)// real// calling react() on a proxy returns itselfconsole.Begin session(reagent(attorney)===attorney)// real

This rule also applies to nested objects. Due to deep reactivity, objects nested inside a reactive object are also proxies:


constantattorney= reagent({})constantcru= {}attorney.nested=cruconsole.Begin session(attorney.nested===cru)// false

limitations ofreagent() #

Losreagent()The API has two limitations:

  1. Only works for object types (objects, arrays, andtypes of collectionasMapyTo establish🇧🇷 can't holdprimitive typesascorda,numberoboleano.

  2. Since Vue's reactivity tracking works on top of property access, we should always keep the same reference to the reactive object. This means that we cannot easily "replace" a reactive object because the reactive connection to the first reference has been lost:


    leavestate= reagent({ tell: 0 })// the old reference ({ count: 0 }) is no longer tracked (lost reactivity connection!)state= reagent({ tell: 1 })

    It also means that when we assign or destructure property of a reactive object to local variables, or when we pass that property to a function, we will lose the reactive connection:


    (Video) Reactivity - general principles

    constantstate= reagent({ tell: 0 })// n is a local variable that is not connected// about status.account.leavenorte=state.tell// does not affect the original statenorte++// count is also disconnected from state.count.leave {tell} =state// does not affect the original statetell++// the function takes a simple number and// will not be able to track changes to state.countcall some function(state.tell)

Reactive variables withreferee() #

To deal with the limitations ofreagent(), Vue also provides areferee()function that allows us to create reagents"ref"which can contain any type of value:


to import { referee } do 'vista'constanttell= referee(0)

referee()takes the argument and returns it inside a ref object with a.valentiaproperty:


constanttell= referee(0)console.Begin session(tell)// {valor: 0}console.Begin session(tell.valeria)// 0tell.valeria++console.Begin session(tell.valeria)// 1

See too:writing references

Similar to the properties of a reactive object, the.valentiaA reference property is reactive. Also, when maintaining object types, ref automatically converts its.valentiaswindlerreagent().

A reference containing an object value can reactively replace the entire object:


constantrefobject= referee({ tell: 0 })// this works reactivelyrefobject.valeria= { tell: 1 }

References can also be passed to functions or destructured from simple objects without losing reactivity:


constantobject= { Foo: referee(1), bar: referee(2)}// the function receives a reference// you need to access the value via .value but// will keep the connection reactivecall some function(objective.Foo)// still reactiveconstant {Foo,bar} =object

In other words,referee()lets you create a "reference" for any value and pass it along without losing reactivity. This capability is very important as it is often used when extracting logic incombinable functions.

Unpacking references in templates#

When references are accessed as top-level properties in the model, they are automatically "unwrapped", so there is no need to use.valentia🇧🇷 Here's the counterexample above, usingreferee()instead of:


<road map context>to import { referee } do 'vista'constanttell= referee(0)Occupation increment() { tell.valeria++}</road map><model> <button@click="increment"> {{tell}} <!-- no .value required --> </button></model>

try it on the playground

Note that unfolding only applies if the reference is a top-level property in the model's rendering context. For example,Fooit's a top-level property, butobjeto.foois not.

So, given the following object:


constantobject= { Foo: referee(1)}

The next expression will beNOwork as expected:


{{object.Foo+ 1 }}

The result obtained will be[object Object]whyobjeto.foois a ref object. We can fix this by doingFooa top-level property:


constant {Foo} =object


{{Foo+ 1 }}
(Video) Vue JS Crash Course

Now the rendering result will be2.

One thing to note is that a reference will also be unwrapped if it is the final evaluated value of a text tween (i.e. a{{ }}label), then the following will represent1:



This is just a text tween convenience feature and is equivalent to{{ }}.

Unpacking references into reactive objects#

When onerefereeaccessed or modified as a property of a reactive object, it is also automatically unpacked to behave like a normal property:


constanttell= referee(0)constantstate= reagent({tell})console.Begin session(state.tell)// 0state.tell= 1console.Begin session(tell.valeria)// 1

If a new reference is assigned to a property linked to an existing reference, it will replace the old reference:


constantother account= referee(2)state.tell=other accountconsole.Begin session(state.tell)// 2// the original reference is now disconnected from state.countconsole.Begin session(tell.valeria)// 1

Ref unfolding only happens when it is nested inside a deep reactive object. Does not apply when accessed as owned by ashallow reactive object.

Unpacking references into arrays and collections#

Unlike reactive objects, no unfolding is performed when the reference is accessed as an element of a reactive array or a native collection type such asMap:


constantbooks= reagent([referee('See 3 Guide')])// need .value hereconsole.Begin session(books[0].valeria)constantmap= reagent(novo Map([['tell', referee(0)]]))// need .value hereconsole.Begin session(map.take it('tell').valeria)

stateful methods#

In some cases, we may need to dynamically create a method function, for example, create a reject event handler:


to import { rebound } do 'lodash-es'export failure { methods: { // Jump with Lodash click: rebound(Occupation () { // ...respond to click... }, 500) }}

However, this approach is problematic for components that are reused because a debounce function is required.with state: keeps some internal state over elapsed time. If multiple component instances share the same rejected role, they will interfere with each other.

To keep the rejection function of each instance of the component independent of the others, we can create the rejection version in thecreatedlifecycle hook:


export failure { created() { // each instance now has its own copy of the removed controller That is.debouncedClick = _.rebound(That, 500) }, disassembled() { // it's also a good idea to cancel the timer // when the component is removed That is.debouncedClick.cancel() }, methods: { click() { // ...respond to click... } }}

reactivity transformation #

have to dress.valentiawith refs is a disadvantage imposed by JavaScript's language limitations. However, with compile-time transformations, we can improve ergonomics by automatically adding.valentiain appropriate locations. Vue provides a compile-time transform that allows us to write the previous "counter" example like this:


<road map context>leavetell= $ ref(0)Occupation increment() { // no .value is required tell++}</road map><model> <button@click="increment">{{tell}}</button></model>

You can learn more aboutreactivity transformationin its dedicated section. Please note that it is currently still experimental and may change before finalization.


1. Reactivity Series of Metals | Environmental | Chemistry | FuseSchool
(FuseSchool - Global Education)
2. Patterns and principles of reactivity - Chemistry details
(Alison Flynn)
3. Patterns and Principles of reactivity - Research and Development
(Alison Flynn)
4. 11 reactivity fundamentals
(Daily New Learn)
5. Making Predictions Using Reactivity Series | Reactions | Chemistry | FuseSchool
(FuseSchool - Global Education)
6. Vue.js Basics Ep. 05 - Components | Props
(RabbitWerks JavaScript)
Top Articles
Latest Posts
Article information

Author: Arielle Torp

Last Updated: 05/25/2023

Views: 6251

Rating: 4 / 5 (41 voted)

Reviews: 80% of readers found this page helpful

Author information

Name: Arielle Torp

Birthday: 1997-09-20

Address: 87313 Erdman Vista, North Dustinborough, WA 37563

Phone: +97216742823598

Job: Central Technology Officer

Hobby: Taekwondo, Macrame, Foreign language learning, Kite flying, Cooking, Skiing, Computer programming

Introduction: My name is Arielle Torp, I am a comfortable, kind, zealous, lovely, jolly, colorful, adventurous person who loves writing and wants to share my knowledge and understanding with you.