Hi, I’m Allyn.

In this series of articles, we will use questions and answers to master vUE development and make progress together. Welcome to discuss in the comments area

The problem

Q 6

Why does data in Vue have to be a function?

7 q

What’s the difference between V-if and V-show?

8 q

Why can’t V-if and V-for be used together?

9 q

Can Vue detect changes when adding or deleting attributes to an object?

10 q

What should be done with data that does not require responsiveness?

Q 11

Can Vue detect a change when it assigns a value directly to an array item?

12 ask

How does VUE trigger an array update?

Q 13

What is the difference between a value returned using computed and a value returned using Method?

Question 14

Can computed data be transmitted?

Ask 15

What are the different uses of computed and watch?

Question 16

Can Watch listen for computed changes?

Q 17

What are the immediate and deep parts of the watch?

answer

6. Why must data in vue be a function?

This ensures the independence and reusability of component data

The following example is taken from the VUE documentation that illustrates this problem.

When we define a

component, you may notice that its data does not provide an object directly like this:

data: { 
  count: 0 
}
Copy the code

A component’s data option must be a function, so each instance can maintain a separate copy of the returned object:

data: function () {
  return {
    count: 0
  }
}
Copy the code

If Vue does not have this rule, clicking a button may affect all other instances as follows:

The essence of this problem is that data is an object, and the object is a reference type. The values of the reference type all point to the same memory address, so the components share the same data when they reuse the data.

function MyButton() {}

MyButton.prototype.data = {
  count: 10
}

const buttonA = new MyButton()
const buttonB = new MyButton()

buttonA.data.count = 20

console.log(buttonA.data.count)   // 20
console.log(buttonB.data.count)   // 20
Copy the code

The code above shows how data is written as an object, changing one place and changing another.

If data is a function that returns an object, it’s different.

function MyButton() {
  this.data = this.data()
}

MyButton.prototype.data = function () {
  return {
    count: 10
  }
}

const buttonA = new MyButton()
const buttonB = new MyButton()

buttonA.data.count = 20

console.log(buttonA.data.count)  // 20
console.log(buttonB.data.count)  // 10
Copy the code

In this way, the data values of the two components are kept separately in closures and do not affect each other.

7. What’s the difference between V-if and V-show?

V-if is “true” conditional rendering because it ensures that event listeners and subcomponents within the conditional block are properly destroyed and rebuilt during the switch.

V-if is also lazy: if the condition is false during initial rendering, nothing is done — the conditional block is not rendered until the condition is true for the first time.

V-show, by contrast, is much simpler — elements are always rendered regardless of initial conditions, and are simply toggled based on CSS (display: None).

In general, V-if has a higher switching overhead, while V-show has a higher initial rendering overhead.

Therefore, v-show is good if you need to switch very frequently; It is better to use V-if if conditions rarely change at run time.

8. Why cannot V-if and V-for be used together?

When Vue processes instructions, V-for has higher precedence than V-if if v-for and V-if are written on the same element, for example:

<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
Copy the code

The following operation will be performed:

this.users.map(function (user) {
  if (user.isActive) {
    return user.name
  }
})
Copy the code

Assuming the Users array has 10,000 entries, but only one user is isActive, the entire Users array will also be traversed.

This is extremely performance unfriendly.

By changing it to iterate over one of the calculated properties as follows:

<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

computed: {
  activeUsers: function () {
    return this.users.filter(function (user) {
      return user.isActive
    })
  }
}

Copy the code

We will gain the following benefits:

  • The filtered listonlyWill be inusersThe array is recalculated only when relevant changes occur, making filtering more efficient.
  • usev-for="user in activeUsers"And then, when we renderonlyMore efficient rendering by traversing active users.
  • Decouple the logic of the render layer, and maintainability (changes and extensions to the logic) is greater.

To achieve the same benefits, we can also combine:

<ul>
  <li
    v-for="user in users"
    v-if="shouldShowUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
Copy the code

Update as follows:

<ul v-if="shouldShowUsers">
  <li
    v-for="user in users"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
Copy the code

By moving v-if to the container element, we no longer check shouldShowUsers for every user in the list. Instead, we only check it once and don’t do v-for if shouldShowUsers is no.

9. Can Vue detect changes when adding or deleting attributes to an object?

Can’t.

<p>{{ obj.name }}</p> <p>{{ obj.age }}</p> <button @click="handleObjChange">change this.obj</button> data() { return { obj: { name: $set(this.obj, 'age', $set(this.obj, 'age', $set(this.obj, 'age', $set), $set(this.obj, 'age', $set), $set(this.obj, 'age', $set), $this.$delete(this.obj, 'name')}Copy the code

When I open the Vue developer tool, I find that the operation on obj actually works, the name attribute is removed and the age attribute is assigned to 25.

The core VUE responsive API Object.defineProperty does not listen to add or delete new attributes to objects, so the view is not updated.

That’s why vUE has two global apis called vue. set and vue. delete.

  • Object cannot add attributes, usingthis.$set(obj, key, val)The new.
  • Object cannot delete properties, usingthis.$delete(obj, key)Delete it.

10. What should be done with data that does not require responsiveness?

In component development, there are always some data that do not need to be processed in a responsive manner, such as some constants, or some static resource data, or some static enumeration values, which can not be directly written into the data to save performance.

Freeze data() {this.consta = 'XXX' this.lista = [] this.obja = {} return {listB: Object.freeze([]), objB: Object.freeze({}), } }Copy the code

The object.freeze () method freezes an Object. A frozen object can no longer be modified. If you freeze an object, you cannot add new attributes to the object, delete existing attributes, modify the enumerability, configurability, writability of existing attributes of the object, or modify the value of existing attributes. In addition, the stereotype of an object cannot be modified after it is frozen. Freeze () returns the same object as the argument passed in.

⚠️ do not use the object. freeze method, which will throw an error and block the program from running, or write a try catch.

11. Can Vue detect changes when assigning an array item directly?

Can’t

<div v-for="item in list" :key="item.name"> {{ item.name }} </div> <button @click="handleArrChange">change this.list</button> data() { return { list: [ { name: 'lin' } ] } } handleArrChange() { this.list[0] = { name: 'wang'} // Views are not updated}Copy the code

Look at the VUE developer tools and see that the data is updated, but the view is not.

Updates can be implemented as follows:

  • Use this.$set(arr, index, value)
 this.$set(this.list, 0, { name: 'wang' })
Copy the code
  • Splice (index, 1, item)
 this.list.splice(0, 1, { name: 'wang' })
Copy the code
  • Using this.$forceUpdate(), force rendering, not recommended.
this.list[0] = { name: 'wang' }
this.$forceUpdate()
Copy the code
  • Using deep copy is also not recommended
import { clone } from 'xe-utils'
...
this.list = clone(this.list, true)
Copy the code
  • Using the Map method
this.list = this.list.map((item, index) => {
  if (index === 0) {
    item.name = 'wang'
  }
  return item
})
Copy the code

12. What are the methods used by Vue to trigger array updates?

  • Push adds one or more elements to the end of the array
this.list.push({ name: 'lin1' })    
this.list.push({ name: 'lin1' },{ name: 'lin2' })
Copy the code
  • Pop removes the last element of the array
this.list.pop()
Copy the code
  • Unshift adds one or more elements to the front of the array
this.list.unshift({ name: 'lin1' })
this.list.unshift({ name: 'lin1' },{ name: 'lin2' })
Copy the code
  • Shift removes the first element of the array
this.list.shift()
Copy the code
  • Array.splice(index, howmany, item1,….. , itemX)
Insert this.list.splice(0, 0, {name: 'lin1'}) instead of this.list.splice(0, 1, {name: 'lin1'})Copy the code
  • The sort order
this.list.sort()
Copy the code
  • Reverse inversion
this.list.reverse()
Copy the code

Why these array methods can trigger view updates is because Vue wraps around the array change methods being listened for.

Methods like Slice, concat, filter, etc., however, do not alter the original array and do not trigger view updates.

13. What is the difference between returns using computed and returns using Method?

<p>{{ reversedMessage }}</p> <p>{{ reversedMessage1() }}</p> <button @click="forceUpdate">forceUpdate</button> ... data() { return { message: 'hello world' } }, computed: {reversedMessage() {console.log(' Perform computed :>> ') return this.message.split('').reverse().join('')}}, methods: {reversedMessage1() {console.log(' execute methods :>> ') return this.message.split('').reverse().join('')}, forceUpdate() { this.$forceUpdate() } }Copy the code

For example, an inverted string can be implemented using computed or method.

When this.$forceUpdate() is executed, only reversedMessage1 in Methods is re-executed, not reversedMessage in computed, because computed is cached, Computed does not recalculate unless the responsive data in it changes.

So, unless you want to avoid caching, you usually return values using computed attributes to avoid recalculation.

14.com Puted Can I send a parameter?

can

<p>{{ totalNum(3) }}</p>

data() {
  return {
    num: 5
  }
},
computed: {
  totalNum(n) {
    return n * this.num
  }
}

Copy the code

If the parameter is directly passed, an error will be reported

If “totalNum is not a function” is displayed, then we can return a function with a closure to implement computed parameter transmission.

computed: {
  totalNum() {
    return function (n) {
      return n * this.num
    }
  }
}
Copy the code

After passing the parameter, will the result be cached?

Add a log to totalNum and test this.$forceUpdate() :

TotalNum () {return function (n) {console.log(' Perform computed parameters ') return n * this.num}}Copy the code

This is recalculated every time forceUpdate is invoked.

Obviously, the cache nature of computed is gone, and writing this is no different from returning values in methods, so maybe that’s why VUE didn’t design for computed passable parameters.

15. What are the different uses of computed and watch?

Computed attribute computed

  • Rely onExisting variableTo calculate a target variable, reducing the amount of computational logic written in the template.
  • withCaching mechanismsIf the dependency value is unchanged, the cache will be read directly without recalculation.
  • Cannot beAsynchronous operations.

The listener watch

  • Used to listen for changes to a variable and execute a callback function,
  • Callbacks can perform any logic, such as asynchronous operations, function throttling, and even DOM manipulation (not recommended).

Watch can do what computed can do, but it makes code simpler with computed, and performs better with a lot of computations.

The watch is more flexible, versatile and powerful, but do as much as you can with computed.

16. Can Watch listen for computed changes?

You can.

<p>{{ reversedMessage }}</p>
<button @click="changeMsg">changeMsg</button>

data() {
  return {
    message: 'hello world'
  }
}
computed: {
  reversedMessage() {
    return this.message.split('').reverse().join('')
  }
}
watch: {
  reversedMessage: {
    handler(val) {
      console.log('reversedMessage val :>> ', val)
    }
  }
}
methods: {
  changeMsg() {
    this.message = 'who are you'
  }
}
Copy the code

Computed, which relies on existing responsive variables to calculate a target variable, is also responsive and can be monitored.

17. What does the watch immediate and deep do?

immdiate

Used with hander, the hander function is executed immediately, without waiting for the value of the monitored variable to change

watch: {
  message: {
    handler(newVal, oldVal) {
      // ...
    },
    immediate: true
  }
}

Copy the code

Usage scenario: When the page is first loaded, it is not executed. The command is executed only when the value changes. In this case, you can run the command immediately.

For example, when created requests data once and when the search value changes, we write:

created(){
  this.getList()
},
watch: {
  searchInputValue(){
    this.getList()
  }
}
Copy the code

I can rewrite it like this

watch: {
  searchInputValue:{
    handler: 'getList',
    immediate: true
  }
}
Copy the code

deep

If you are listening on an object type, watch will not execute when you manually modify an attribute of the object.

The deep attribute is available.

data:{
  userInfo:{
    name: 'lin'
  }
},
watch:{
  userInfo: {
    handler(newVal, oldVal){
      // ...
    },
    deep:true 
  }
}
Copy the code

If deep is true, the name change in userInfo will be detected.

It’s going to go through the layers, and it’s going to append this listener to all the properties of this object. However, the performance overhead is high. Modifying any property triggers the handler in this listener.

Deep attribute optimization

You can use string listening.

watch:{
  'userInfo.name': {
    handler(newVal, oldVal){
      // ...
    },
    deep:true 
  }
}
Copy the code

Vue then parses one layer at a time until it encounters the attribute name and then sets a listener for name.

conclusion

Usually wait for the back-end syndication, often wait for an hour, and then the interface still reported an error, it is better to use these time, sum up some knowledge.

The problem is a bit messy, see what or think of what to write demo try, and then summarize into an article, behind slowly sort it out!