Skip to content

Commit 111bcb1

Browse files
committed
Revert inplace update in v-repeat
Inplace update is causing unwanted behavior in multiple existing use cases, and the perf gain is not substantial enough since the cases where it works properly are quite few.
1 parent efedd6e commit 111bcb1

File tree

2 files changed

+2
-147
lines changed

2 files changed

+2
-147
lines changed

src/directives/repeat.js

+2-108
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
var _ = require('../util')
2-
var config = require('../config')
32
var isObject = _.isObject
43
var isPlainObject = _.isPlainObject
54
var textParser = require('../parsers/text')
@@ -39,9 +38,6 @@ module.exports = {
3938
this.template = this.el.tagName === 'TEMPLATE'
4039
? templateParser.parse(this.el, true)
4140
: this.el
42-
// check if we need to use diff instead of inplace
43-
// updates
44-
this.checkUpdateStrategy()
4541
// check other directives that need to be handled
4642
// at v-repeat level
4743
this.checkIf()
@@ -54,38 +50,6 @@ module.exports = {
5450
this.cache = Object.create(null)
5551
},
5652

57-
/**
58-
* Check what strategy to use for updates.
59-
*
60-
* If the repeat is simple enough we can use in-place
61-
* updates which simply overwrites existing instances'
62-
* data. This strategy reuses DOM nodes and instances
63-
* as much as possible.
64-
*
65-
* There are two situations where we have to use the
66-
* more complex but more accurate diff algorithm:
67-
* 1. We are using components with or inside v-repeat.
68-
* The components could have private state that needs
69-
* to be preserved across updates.
70-
* 2. We have transitions on the list, which requires
71-
* precise DOM re-positioning.
72-
*/
73-
74-
checkUpdateStrategy: function () {
75-
var components = Object.keys(this.vm.$options.components)
76-
var matcher
77-
if (components.length) {
78-
matcher = new RegExp(
79-
components.map(function (name) {
80-
return '<' + name + '(>|\\s)'
81-
}).join('|') + '|' + config.prefix + 'component'
82-
)
83-
}
84-
this.needDiff =
85-
(matcher && matcher.test(this.template.outerHTML)) ||
86-
this.el.hasAttribute(config.prefix + 'transition')
87-
},
88-
8953
/**
9054
* Warn against v-if usage.
9155
*/
@@ -181,9 +145,7 @@ module.exports = {
181145
} else if (type === 'string') {
182146
data = _.toArray(data)
183147
}
184-
this.vms = this.needDiff
185-
? this.diff(data, this.vms)
186-
: this.inplaceUpdate(data, this.vms)
148+
this.vms = this.diff(data, this.vms)
187149
// update v-ref
188150
if (this.refID) {
189151
this.vm.$[this.refID] = this.vms
@@ -195,43 +157,6 @@ module.exports = {
195157
}
196158
},
197159

198-
/**
199-
* Inplace update that maximally reuses existing vm
200-
* instances and DOM nodes by simply swapping data into
201-
* existing vms.
202-
*
203-
* @param {Array} data
204-
* @param {Array} oldVms
205-
* @return {Array}
206-
*/
207-
208-
inplaceUpdate: function (data, oldVms) {
209-
oldVms = oldVms || []
210-
var vms
211-
var dir = this
212-
var alias = dir.arg
213-
var converted = dir.converted
214-
if (data.length < oldVms.length) {
215-
oldVms.slice(data.length).forEach(function (vm) {
216-
vm.$destroy(true)
217-
})
218-
vms = oldVms.slice(0, data.length)
219-
overwrite(data, vms, alias, converted)
220-
} else if (data.length > oldVms.length) {
221-
var newVms = data.slice(oldVms.length).map(function (data, i) {
222-
var vm = dir.build(data, i + oldVms.length)
223-
vm.$before(dir.ref)
224-
return vm
225-
})
226-
overwrite(data.slice(0, oldVms.length), oldVms, alias, converted)
227-
vms = oldVms.concat(newVms)
228-
} else {
229-
overwrite(data, oldVms, alias, converted)
230-
vms = oldVms
231-
}
232-
return vms
233-
},
234-
235160
/**
236161
* Diff, based on new data and old data, determine the
237162
* minimum amount of DOM manipulations needed to make the
@@ -440,9 +365,7 @@ module.exports = {
440365
var vm
441366
while (i--) {
442367
vm = this.vms[i]
443-
if (this.needDiff) {
444-
this.uncacheVm(vm)
445-
}
368+
this.uncacheVm(vm)
446369
vm.$destroy()
447370
}
448371
}
@@ -613,33 +536,4 @@ function range (n) {
613536
ret[i] = i
614537
}
615538
return ret
616-
}
617-
618-
/**
619-
* Helper function to overwrite new data Array on to
620-
* existing vms. Used in `inplaceUpdate`.
621-
*
622-
* @param {Array} arr
623-
* @param {Array} vms
624-
* @param {String|undefined} alias
625-
* @param {Boolean} converted
626-
*/
627-
628-
function overwrite (arr, vms, alias, converted) {
629-
var vm, data, raw
630-
for (var i = 0, l = arr.length; i < l; i++) {
631-
vm = vms[i]
632-
data = raw = arr[i]
633-
if (converted) {
634-
vm.$key = data.$key
635-
raw = data.$value
636-
}
637-
if (alias) {
638-
vm[alias] = raw
639-
} else if (!isObject(raw)) {
640-
vm.$value = raw
641-
} else {
642-
vm._setData(raw)
643-
}
644-
}
645539
}

test/unit/specs/directives/repeat_spec.js

-39
Original file line numberDiff line numberDiff line change
@@ -718,45 +718,6 @@ if (_.inBrowser) {
718718
}
719719
})
720720

721-
it('should use diff when block contains component', function (done) {
722-
var spy = jasmine.createSpy()
723-
var obj = { a: 1, b: 2 }
724-
var vm = new Vue({
725-
el: el,
726-
template:
727-
'<div v-repeat="list">' +
728-
'<test-foo v-with="foo: parentFoo"></test-foo>' +
729-
'<div v-component="test-foo" v-with="foo: parentFoo"></div>' +
730-
'</div>',
731-
data: {
732-
list: [1,2]
733-
},
734-
compiled: function () {
735-
this.$set('parentFoo', obj)
736-
},
737-
components: {
738-
'test-foo': {
739-
template: '{{foo.a}}',
740-
watch: {
741-
foo: spy
742-
}
743-
}
744-
}
745-
})
746-
747-
_.nextTick(function () {
748-
expect(spy).toHaveBeenCalledWith(obj, undefined)
749-
expect(spy.calls.count()).toBe(4)
750-
expect(el.innerHTML).toBe([1,2].map(function () {
751-
return '<div>' +
752-
'<test-foo>1</test-foo><!--v-component-->' +
753-
'<div>1</div><!--v-component-->' +
754-
'</div>'
755-
}).join('') + '<!--v-repeat-->')
756-
done()
757-
})
758-
})
759-
760721
})
761722
}
762723

0 commit comments

Comments
 (0)