How much do you know about Vue updating array items

Plutchar. 2020-11-12 10:47:07
know vue updating array items


vue How to update an item in an array , This is a common problem in development

for example :data There's a list Array , There are three items in the array

export default {
data() {
return {
list: [
'foo',
'bar',
'baz'
]
}
}
}

How to update the value of the second item to 'jerry'

Many of my friends may have tried this.list[1] = 'jerry' , Unfortunately, the page doesn't update
This approach has really changed list[1] Value , But there's no way to trigger page updates

So in Vue in , How to update an item in an array ? Here are some ways to sum up :

Array native methods

Array.prototype.splice It's called the most powerful method of arrays , With delete 、 increase 、 Replacement function , It can be used splice To update

this.list.splice(1, 1, 'jerry')

Why? splice Can trigger updates ?
Vue The array that will be listened to ( Here is the list) The change method of the package , So they will also trigger view updates . These wrapped methods include :

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

splice It's no longer an array native method , It is Vue The rewritten method
Part of the source code :

const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
// notify change
ob.dep.notify()
return result
})
})

You can see ,splice In addition to executing its own logic (original.apply(this, args)) outside , It turns the inserted value into a responsive object (observeArray(inserted)), And then call ob.dep.notify() Manually trigger dependency notification .
details src/core/observer/array.js

official API Vue.set()

Vue.set It's an official overall picture API, Alias vm.$set, Used to trigger the response actively

Vue.set(this.list, 1, 'jerry')
// perhaps
this.$set(this.list, 1, 'jerry')

Actually set Method is still called in essence splice Method to trigger the response , Part of the source code

function set (target: Array<any> | Object, key: any, val: any): any {
// ...
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
}
// ...
}

When set When the first parameter of is an array , Call directly target.splice()
details src/core/observer/index.js

vm.$forceUpdate()

To compel Vue Instance re rendering , Actually this.list[1] = 'jerry' operation ,list It has indeed changed , We call vm.$forceUpdate() You can force rendering

this.list[1] = 'jerry'
this.$forceUpdate()

Usually you should avoid using this method , It's done in a normal way, data driven

When you have no way to go , Try this method , But this method should not be abused , Imagine that you just want to change an array item , But it may have updated the entire component

As the official website said :

If you find yourself in need of Vue Do a forced update in ,99.9% The situation of , You did something wrong somewhere .

Deep copy

Generally, the roughest way is through Serialize and then deserialize Come back To achieve

this.list[1] = 'jerry'
this.list = JSON.parse(JSON.stringify(this.list))

Maybe you'll encapsulate your own cloneDeep Method , Although it can trigger a response , But just updating an item requires deep copy , It's a bit awkward

map()

map Is the native method of an array , Used for array mapping , A similar non change approach ( It doesn't change the original array ) also sliceconcatfilter these , They don't change the original array , And always returns a new array
So in Vue We can also update the array by replacing it directly

this.list = this.list.map((item, index) => {
if (index === 1) {
return 'jerry'
}
return item
})

You may think that this will lead to Vue Discard the existing DOM And re render the entire list . Fortunately, ,Vue Do enough .Vue In order to make DOM Elements are reused to the maximum extent, and some intelligent heuristics are implemented , So it is very efficient to replace the original array with an array containing the same elements . Remember to use... In the template v-for You have to provide key Do you ,Vue According to this key Values can be used to find differences more efficiently , Pinpoint and update .

actually , This is based on source data to generate new data ( At the same time, it doesn't affect the outside ) The way to meet the idea of functional programming , If you used redux, So I'm writing reducer You will often use mapfilter these

When an array item is an object

You may encounter this.list[1].name = 'jerry' This situation , If the array item is an object , Then you can directly update the properties of this object by subscript
It's actually Vue We did some processing when initializing the array , If the array item is not an object, it will directly return , No operation , If it's an object , Then I can use Observer Class initializes it , Add... To the object properties gettersetter Monitor
Part of the source code :

class Observer {
value: any;
dep: Dep;
vmCount: number; // number of vms that have this object as root $data
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__', this)
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
} else {
this.walk(value)
}
}
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
observeArray (items: Array<any>) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}

Observer Class initialization , If it's an array , In general, it will call protoAugment()observeArray().protoAugment Will value( Array ) Of __proto__ Point to arrayMethods, Here we focus on observeArray, It calls observe(),observe as follows :

export function observe (value: any, asRootData: ?boolean): Observer | void {
if (!isObject(value) || value instanceof VNode) {
return
}
let ob: Observer | void
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value)
}
if (asRootData && ob) {
ob.vmCount++
}
return ob
}

You can see , If the array item is not an object , Will go straight back to ; Array items are objects , Will continue with the object Observer initialization , And then call walk(), Call... For each property defineReactive(),
defineReactive Will pass Object.defineProperty Add... To attributes gettersetter Monitor , So reassigning an array item triggers the response
details src/core/observer/index.js

About why Vue No will arr[index] = val Become responsive , There's a lot of discussion online , The author also answers , In general , Namely The cost of performance is not directly proportional to the user experience .
arr[index] = val Although not responsive , But there are also official offers API To operate , As a framework ,Vue Enough has been done . Of course Vue3 take Object.defineProperty Instead of Proxy, Then the problem is gone .

版权声明
本文为[Plutchar.]所创,转载请带上原文链接,感谢

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple