Reactivity Fundamentals of Vue3 official document translation

introduction

Suddenly I didn't know what was written in this chapter. I felt the content was a little dry. I took care of the translation and didn't absorb it To sum up, it is mainly about how to combine the responsive object with the template. The responsive object is realized through the proxy object of JavaScript; The objects of response are divided into deep response and shallow response; The completion of responsive objects will have limitations when they are used as function parameters or deconstructed. Therefore, ref() is proposed to avoid this problem, and the unpacking problem of ref is followed

Original address: http://blog.duhbb.com/2022/02/11/translation-of-reactivity-fundamentals-in-vue-3-offiicial-doc/

Welcome to my blog: http://blog.duhbb.com/

Reactivity Fundamentals of Vue3 official document translation

Reactivity Fundamentals: I don't know how to translate it. Just take it as the principle or basis of responsiveness

P.S. the version I see is Composition API, so if there is any deviation, it should be the difference in API style. Please identify it yourself

Declare the state of the response

We can use the reactive() function to create a responsive object or array

Wonderful. What happens after it's created?

import { reactive } from 'vue'

const state = reactive({ count: 0 })

The objects in response are JavaScript proxy object , those who have studied proxy mode should understand it. No one thinks that using common objects can be responsive. I forced it blindly

But these proxy objects look no different from ordinary objects The difference is that Vue can track the property access of proxy objects and the change of responsive objects If you are curious about the implementation principle in Vue, I recommend you to understand it Reactivity in Depth , don't be in a hurry. Finish reading this article first, and then get to know it better

You can also refer to: Typing Reactive

To use a responsive object in a component template, declare and return this object from the component's setup() function

P.S. Options API should be returned from data()

import { reactive } from 'vue'

export default {
  // `setup ` is a special hook specially used for composition API
  setup() {
    const state = reactive({ count: 0 })

    // Expose reactive state to template
    return {
      state
    }
  }
}

In this way, state is associated with template. Look at what a awesome framework

<div>{{ state.count }}</div>

Similarly, we can declare a function in the same domain to manipulate the responsive state, and expose it as a method and state

import { reactive } from 'vue'

export default {
  setup() {
    const state = reactive({ count: 0 })

    // Wipe, the function of mutation is put in scope?
    function increment() {
      state.count++
    }

    // don't forget to expose the function as well.
    return {
      state,
      increment
    }
  }
}

The exposed methods are generally listeners that respond to events:

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

<script setup>

Manually exposing responsive objects or methods through setup may be cumbersome

Fortunately, you only need to do this when you don't need the build step

When using single file component, we can greatly simplify it through < script setup >:

<!-- Crooked day, It's really convenient -->
<script setup>
import { reactive } from 'vue'

const state = reactive({ count: 0 })

function increment() {
  state.count++
}
</script>

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

The top-level introduction and variables in < script setup > will become available in the template of the same component

In the rest of this document, we will mainly use SFC + < script setup > syntax to write code examples of Composition API style. This usage should be the most commonly used by Vue developers

I'm a fake front-end, fake Vue Developer

DOM update Timing

Sorry, timing, I can't translate. I think it should mean "timing"

When you modify a responsive object, the DOM is automatically updated But, however, you should note that DOM updates are not synchronized

Shocking news??? What? Why can't I synchronize with this update?

In fact, Vue will buffer these changes until the next update cycle of "next click" to ensure that each component is updated only once (I wipe, which is the whole clock cycle?), No matter how you modify the state

Yo, how do you play?

In order to complete all DOM update s after the state is modified, you can use nextTick() This API:

import { nextTick } from 'vue'

function increment() {
  count.value++
  // The callback of nextTick indicates that all the components in the DOM have been updated?
  nextTick(() => {
    // access updated DOM
  })
}

Deeper responsiveness

In Vue, state defaults to deep response

This means that this response can be detected even when you modify nested objects or objects in an array

(sure enough, it's a deep copy concept, so nested objects and arrays are also proxy? The proxy mode is really awesome, and the Spring framework also depends on the proxy mode)

import { reactive } from 'vue'

const obj = reactive({
  nested: { count: 0 },
  arr: ['foo', 'bar']
})

function mutateDeeply() {
  // these will work as expected.
  obj.nested.count++
  obj.arr.push('baz')
}

Of course, you can explicitly create Shallow response object , then only the changes of the object of the root node will be tracked, but this abnormal usage is only used in advanced places, ah, no, advanced scenes

Responsive proxy object VS. original object

You should pay attention to the expression of the original object of the object type returned from the reactive() method agent , is not equivalent to the original object

const raw = {}
const proxy = reactive(raw)

// proxy is NOT equal to the original.
console.log(proxy === raw) // false

Only the proxy object is reactive, and modifying the original object will not trigger the update Hidden Thorn: the best way to use Vue responsive system is to use the proxy object of your state. Don't directly operate the original object (I added later)

In order to ensure the consistency of access to proxy objects, the same proxy object is always returned by using reactive() for the same object. Wow, even, this thing is still idempotent. Similarly, when using reactive() method for the other party, it returns itself (it should be well understood)

// calling reactive() on the same object returns the same proxy
console.log(reactive(raw) === proxy) // true

// calling reactive() on a proxy returns itself
console.log(reactive(proxy) === proxy) // true

The same rule applies to nested objects Because it is deeply responsive, nested objects in responsive objects are also proxy:

const proxy = reactive({})

const raw = {}
proxy.nested = raw

console.log(proxy.nested === raw) // false

Limitations of the reactive() function

The awesome function of reactive() also has its limitations:

  1. It can only act on object types (object, array or collection types, such as Map and Set) It cannot work on primitive types, such as string, number or boolean Don't you have to unpack
  2. Due to the access of Vue's responsive tracking property, we keep the same reference to the responsive object This means that we cannot replace responsive objects:
let state = reactive({ count: 0 })

// this won't work!
state = reactive({ count: 1 })

This also means that when we assign or deconstruct the attribute of a responsive object to a local variable, or when we pass the attribute to a function, or deconstruct the attribute from a responsive object, we will lose the responsive link (good! It feels a bit like a duck like Hibernate's state management, de attach):

const state = reactive({ count: 0 })

// n is a local variable that is disconnected
// from state.count.
let n = state.count
// does not affect original state
n++

// count is also disconnected from state.count.
let { count } = state
// does not affect original state
count++

// the function receives a plain number and
// won't be able to track changes to state.count
callSomeFunction(state.count)

Get the response variable through ref() (about that?)

In order to solve the inconvenience of reactive(), Vue also provides a ref() function, which allows us to create responsive references of any value type:

import { ref } from 'vue'

const count = ref(0)

ref() accepts parameters and returns a ref object with the property value:

const count = ref(0)

console.log(count) // { value: 0 }
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

P.S.: what he mews is packing and unpacking?

reference resources: Typing Refs

Similar to the properties of a responsive object, ref is The value attribute is also responsive In addition, when holding an object type in your hand, ref will automatically Value is handed over to reactive()

The object value contained in ref can responsively replace the whole object (don't understand?):

const objectRef = ref({ count: 0 })

// this works reactively
objectRef.value = { count: 1 }

Oh, I see. Isn't reactive() irreplaceable? ref can be replaced

refs can be passed into functions or deconstructed from ordinary objects without losing reactivity:

const obj = {
  foo: ref(1),
  bar: ref(2)
}

// the function receives a ref
// it needs to access the value via .value but it
// will retain the reactivity connection
callSomeFunction(obj.foo)

// still reactive
const { foo, bar } = obj

In other words, ref() allows us to create a reference to anything that is worth while passing her without losing reactivity

This feature is very important in extracting logic into Composable Functions It's very important when you're young

Reference unpacking in the template

They will not be used as top-level attributes when we need them It's worth it The example counted before is modified with ref():

<script setup>
import { ref } from 'vue'

/* Hey, hey, it's time to get the original value */
const count = ref(0)

function increment() {
  count.value++
}
</script>

<template>
  <button @click="increment">
    {{ count }} <!-- no .value needed -->
  </button>
</template>

Caution: automatic unpacking only applies to top-level attributes, and nested access to refs will not be unpacked:

const object = { foo: ref(1) }
<!-- object Just an ordinary object, The rules just said that only top-level Will be unpacked automatically -->
{{ object.foo }} <!-- does NOT get unwrapped -->

As expected, foo will not be unpacked. Hehe, I haven't verified it yet

Unpacking of ref s in responsive objects

When a ref is accessed or modified as the attribute of a responsive object, it will be unpacked automatically, just like the normal attribute:

const count = ref(0)

/* state It is already a responsive object. It has an attribute in the form of ref, which will be unpacked automatically. It doesn't need to be top level */
/* I feel I have understood this, but I haven't practiced it */
const state = reactive({
  count
})

console.log(state.count) // 0

state.count = 1
console.log(count.value) // 1

If a new ref replaces the original ref, it will replace the original Ref:

const otherCount = ref(2)

state.count = otherCount
console.log(state.count) // 2
// original ref is now disconnected from state.count
console.log(count.value) // 1

The unpacking of ref only occurs when it is a deep responsive object, not as Shallow response object Will not be unpacked

Unpacking of ref s in arrays and collections

Unlike responsive objects, unpacking does not occur when ref is accessed as an element of a responsive array or collection type (why?):

const books = reactive([ref('Vue 3 Guide')])
// need .value here
console.log(books[0].value)

const map = reactive(new Map([['count', ref(0)]]))
// need .value here
console.log(map.get('count').value)

Transitivity of response (experimental characteristics)

Must be The restrictions imposed by JavaScript when value and refs are used together However, it is added at the appropriate position through the conversion during operation Value can improve ergonomics Vue provides compile time conversion so that we can write the previous "counter" example as follows:

<script setup>
let count = $ref(0)

function increment() {
  // no need for .value
  count++
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>

about Reactivity Transform You can learn about it in her topic and remind you that this is only an experimental drop at present

Concluding remarks

Suddenly I didn't know what was written in this chapter. I felt the content was a little dry. I took care of the translation and didn't absorb it To sum up, it is mainly about how to combine the responsive object with the template. The responsive object is realized through the proxy object of JavaScript; The objects of response are divided into deep response and shallow response; The completion of responsive objects will have limitations when they are used as function parameters or deconstructed. Therefore, ref() is proposed to avoid this problem, and the unpacking problem of ref is followed

Original address: http://blog.duhbb.com/2022/02/11/translation-of-reactivity-fundamentals-in-vue-3-offiicial-doc/

Welcome to my blog: http://blog.duhbb.com/

Keywords: Javascript Front-end Vue Vue.js

Added by dmphotography on Sat, 12 Feb 2022 00:19:22 +0200