diff --git a/src/core/observer/scheduler.js b/src/core/observer/scheduler.js index ceaa2f7c..f6d762b5 100644 --- a/src/core/observer/scheduler.js +++ b/src/core/observer/scheduler.js @@ -82,7 +82,7 @@ function runSchedulerQueue (queue: Array) { if (circular[id] > config._maxUpdateCount) { warn( 'You may have an infinite update loop ' + ( - watcher === watcher.vm._watcher + watcher === watcher.vm && watcher.vm._watcher ? `in a component render function.` : `in watcher with expression "${watcher.expression}"` ), diff --git a/src/core/vdom/create-element.js b/src/core/vdom/create-element.js index bc5ceca7..8ea0181e 100644 --- a/src/core/vdom/create-element.js +++ b/src/core/vdom/create-element.js @@ -37,6 +37,14 @@ function _createElement ( ) return } + if (data && data.__ob__) { + process.env.NODE_ENV !== 'production' && warn( + `Avoid using observed data object as vnode data: ${JSON.stringify(data)}\n` + + 'Always create fresh vnode data objects in each render!', + context + ) + return + } if (!tag) { // in case of component :is set to falsy value return emptyVNode() diff --git a/src/platforms/web/runtime/modules/attrs.js b/src/platforms/web/runtime/modules/attrs.js index 41f2034f..7ca6a137 100644 --- a/src/platforms/web/runtime/modules/attrs.js +++ b/src/platforms/web/runtime/modules/attrs.js @@ -17,9 +17,10 @@ function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) { const elm = vnode.elm const oldAttrs = oldVnode.data.attrs || {} const attrs = vnode.data.attrs || {} + const clonedAttrs = vnode.data.attrs = {} for (key in attrs) { - cur = attrs[key] + cur = clonedAttrs[key] = attrs[key] old = oldAttrs[key] if (old !== cur) { setAttr(elm, key, cur) diff --git a/src/platforms/web/runtime/modules/props.js b/src/platforms/web/runtime/modules/props.js index 04688924..041647e3 100644 --- a/src/platforms/web/runtime/modules/props.js +++ b/src/platforms/web/runtime/modules/props.js @@ -8,6 +8,7 @@ function updateProps (oldVnode: VNodeWithData, vnode: VNodeWithData) { const elm: any = vnode.elm const oldProps = oldVnode.data.props || {} const props = vnode.data.props || {} + const clonedProps = vnode.data.props = {} for (key in oldProps) { if (props[key] == null) { @@ -15,7 +16,7 @@ function updateProps (oldVnode: VNodeWithData, vnode: VNodeWithData) { } } for (key in props) { - cur = props[key] + cur = clonedProps[key] = props[key] if (key === 'value') { // store value as _value as well since // non-string values will be stringified diff --git a/src/platforms/web/runtime/modules/style.js b/src/platforms/web/runtime/modules/style.js index a6b99411..06c94404 100644 --- a/src/platforms/web/runtime/modules/style.js +++ b/src/platforms/web/runtime/modules/style.js @@ -1,6 +1,6 @@ /* @flow */ -import { cached, camelize, toObject, extend } from 'shared/util' +import { cached, camelize, toObject } from 'shared/util' const prefixes = ['Webkit', 'Moz', 'ms'] @@ -31,24 +31,25 @@ function updateStyle (oldVnode: VNodeWithData, vnode: VNodeWithData) { // handle array syntax if (Array.isArray(style)) { - style = vnode.data.style = toObject(style) + style = toObject(style) } + // clone the style for future updates, + // in case the user mutates the style object in-place. + const clonedStyle = vnode.data.style = {} + for (name in oldStyle) { if (!style[name]) { elm.style[normalize(name)] = '' } } for (name in style) { - cur = style[name] + cur = clonedStyle[name] = style[name] if (cur !== oldStyle[name]) { // ie9 setting to null has no effect, must use empty string elm.style[normalize(name)] = cur || '' } } - // clone the style for future updates, - // in case the user mutates the style object in-place. - vnode.data.style = extend({}, style) } export default {