Skip to content

Commit f0aef75

Browse files
committed
warn observed vnode data + handle in place mutations for vdom modules (ref #3276)
1 parent e6dcd21 commit f0aef75

File tree

5 files changed

+20
-9
lines changed

5 files changed

+20
-9
lines changed

src/core/observer/scheduler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function runSchedulerQueue (queue: Array<Watcher>) {
8282
if (circular[id] > config._maxUpdateCount) {
8383
warn(
8484
'You may have an infinite update loop ' + (
85-
watcher === watcher.vm._watcher
85+
watcher === watcher.vm && watcher.vm._watcher
8686
? `in a component render function.`
8787
: `in watcher with expression "${watcher.expression}"`
8888
),

src/core/vdom/create-element.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ function _createElement (
3737
)
3838
return
3939
}
40+
if (data && data.__ob__) {
41+
process.env.NODE_ENV !== 'production' && warn(
42+
`Avoid using observed data object as vnode data: ${JSON.stringify(data)}\n` +
43+
'Always create fresh vnode data objects in each render!',
44+
context
45+
)
46+
return
47+
}
4048
if (!tag) {
4149
// in case of component :is set to falsy value
4250
return emptyVNode()

src/platforms/web/runtime/modules/attrs.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) {
1717
const elm = vnode.elm
1818
const oldAttrs = oldVnode.data.attrs || {}
1919
const attrs = vnode.data.attrs || {}
20+
const clonedAttrs = vnode.data.attrs = {}
2021

2122
for (key in attrs) {
22-
cur = attrs[key]
23+
cur = clonedAttrs[key] = attrs[key]
2324
old = oldAttrs[key]
2425
if (old !== cur) {
2526
setAttr(elm, key, cur)

src/platforms/web/runtime/modules/props.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ function updateProps (oldVnode: VNodeWithData, vnode: VNodeWithData) {
88
const elm: any = vnode.elm
99
const oldProps = oldVnode.data.props || {}
1010
const props = vnode.data.props || {}
11+
const clonedProps = vnode.data.props = {}
1112

1213
for (key in oldProps) {
1314
if (props[key] == null) {
1415
elm[key] = undefined
1516
}
1617
}
1718
for (key in props) {
18-
cur = props[key]
19+
cur = clonedProps[key] = props[key]
1920
if (key === 'value') {
2021
// store value as _value as well since
2122
// non-string values will be stringified

src/platforms/web/runtime/modules/style.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* @flow */
22

3-
import { cached, camelize, toObject, extend } from 'shared/util'
3+
import { cached, camelize, toObject } from 'shared/util'
44

55
const prefixes = ['Webkit', 'Moz', 'ms']
66

@@ -31,24 +31,25 @@ function updateStyle (oldVnode: VNodeWithData, vnode: VNodeWithData) {
3131

3232
// handle array syntax
3333
if (Array.isArray(style)) {
34-
style = vnode.data.style = toObject(style)
34+
style = toObject(style)
3535
}
3636

37+
// clone the style for future updates,
38+
// in case the user mutates the style object in-place.
39+
const clonedStyle = vnode.data.style = {}
40+
3741
for (name in oldStyle) {
3842
if (!style[name]) {
3943
elm.style[normalize(name)] = ''
4044
}
4145
}
4246
for (name in style) {
43-
cur = style[name]
47+
cur = clonedStyle[name] = style[name]
4448
if (cur !== oldStyle[name]) {
4549
// ie9 setting to null has no effect, must use empty string
4650
elm.style[normalize(name)] = cur || ''
4751
}
4852
}
49-
// clone the style for future updates,
50-
// in case the user mutates the style object in-place.
51-
vnode.data.style = extend({}, style)
5253
}
5354

5455
export default {

0 commit comments

Comments
 (0)