diff --git a/packages/runtime-core/src/createRenderer.ts b/packages/runtime-core/src/createRenderer.ts index e16424f6..d749f497 100644 --- a/packages/runtime-core/src/createRenderer.ts +++ b/packages/runtime-core/src/createRenderer.ts @@ -7,7 +7,6 @@ import { MountedVNode, RenderNode, createTextVNode, - cloneVNode, Ref, VNodeChildren } from './vdom' @@ -135,10 +134,6 @@ export function createRenderer(options: RendererOptions) { endNode: RenderNode | null ) { for (let i = 0; i < children.length; i++) { - let child = children[i] - if (child.el) { - children[i] = child = cloneVNode(child) - } mount(children[i], container, contextVNode, isSVG, endNode) } } @@ -346,6 +341,11 @@ export function createRenderer(options: RendererOptions) { contextVNode: MountedVNode | null, isSVG: boolean ) { + if (prevVNode === nextVNode) { + nextVNode.el = prevVNode.el + return + } + const nextFlags = nextVNode.flags const prevFlags = prevVNode.flags @@ -768,19 +768,12 @@ export function createRenderer(options: RendererOptions) { for (i; i < commonLength; i++) { nextChild = nextChildren[i] prevChild = prevChildren[i] - if (nextChild.el) { - nextChildren[i] = nextChild = cloneVNode(nextChild) - } patch(prevChild, nextChild, container, contextVNode, isSVG) prevChildren[i] = nextChild as MountedVNode } if (prevLength < nextLength) { for (i = commonLength; i < nextLength; i++) { - nextChild = nextChildren[i] - if (nextChild.el) { - nextChildren[i] = nextChild = cloneVNode(nextChild) - } - mount(nextChild, container, contextVNode, isSVG, endNode) + mount(nextChildren[i], container, contextVNode, isSVG, endNode) } } else if (prevLength > nextLength) { for (i = commonLength; i < prevLength; i++) { @@ -810,9 +803,6 @@ export function createRenderer(options: RendererOptions) { outer: { // Sync nodes with the same key at the beginning. while (prevVNode.key === nextVNode.key) { - if (nextVNode.el) { - nextChildren[j] = nextVNode = cloneVNode(nextVNode) - } patch(prevVNode, nextVNode, container, contextVNode, isSVG) prevChildren[j] = nextVNode as MountedVNode j++ @@ -828,9 +818,6 @@ export function createRenderer(options: RendererOptions) { // Sync nodes with the same key at the end. while (prevVNode.key === nextVNode.key) { - if (nextVNode.el) { - nextChildren[nextEnd] = nextVNode = cloneVNode(nextVNode) - } patch(prevVNode, nextVNode, container, contextVNode, isSVG) prevChildren[prevEnd] = nextVNode as MountedVNode prevEnd-- @@ -849,11 +836,7 @@ export function createRenderer(options: RendererOptions) { const nextNode = nextPos < nextLength ? nextChildren[nextPos].el : endNode while (j <= nextEnd) { - nextVNode = nextChildren[j] - if (nextVNode.el) { - nextChildren[j] = nextVNode = cloneVNode(nextVNode) - } - j++ + nextVNode = nextChildren[j++] mount(nextVNode, container, contextVNode, isSVG, nextNode) } } @@ -896,9 +879,6 @@ export function createRenderer(options: RendererOptions) { } else { pos = j } - if (nextVNode.el) { - nextChildren[j] = nextVNode = cloneVNode(nextVNode) - } patch(prevVNode, nextVNode, container, contextVNode, isSVG) patched++ break @@ -940,9 +920,6 @@ export function createRenderer(options: RendererOptions) { } else { pos = j } - if (nextVNode.el) { - nextChildren[j] = nextVNode = cloneVNode(nextVNode) - } patch(prevVNode, nextVNode, container, contextVNode, isSVG) patched++ } else if (!canRemoveWholeContent) { @@ -971,9 +948,6 @@ export function createRenderer(options: RendererOptions) { if (sources[i] === 0) { pos = i + nextStart nextVNode = nextChildren[pos] - if (nextVNode.el) { - nextChildren[pos] = nextVNode = cloneVNode(nextVNode) - } nextPos = pos + 1 mount( nextVNode, @@ -1002,9 +976,6 @@ export function createRenderer(options: RendererOptions) { if (sources[i] === 0) { pos = i + nextStart nextVNode = nextChildren[pos] - if (nextVNode.el) { - nextChildren[pos] = nextVNode = cloneVNode(nextVNode) - } nextPos = pos + 1 mount( nextVNode, @@ -1119,8 +1090,8 @@ export function createRenderer(options: RendererOptions) { } else { platformRemoveChild(container, el) } - ;(vnode as any).el = null } + ;(vnode as any).el = null } function removeChildren( @@ -1394,9 +1365,6 @@ export function createRenderer(options: RendererOptions) { container: any ): ComponentInstance | null { const prevVNode = container.vnode - if (vnode && vnode.el) { - vnode = cloneVNode(vnode) - } if (prevVNode == null) { if (vnode) { mount(vnode, container, null, false, null) diff --git a/packages/runtime-core/src/optional/memoize.ts b/packages/runtime-core/src/optional/memoize.ts new file mode 100644 index 00000000..0bfca68b --- /dev/null +++ b/packages/runtime-core/src/optional/memoize.ts @@ -0,0 +1,53 @@ +// Used for memoizing trees inside render functions. +// +// Example (equivalent of v-once): +// +// render() { +// return memoize(h('div', this.msg), this, 0) +// } +// +// Memoize baesd on keys: +// +// render() { +// return memoize(h('div', this.msg + this.count), this, 0, [this.msg]) +// } + +import { Component } from '../component' +import { warn } from '../warning' + +const memoizeMap = new WeakMap() + +export function memoize( + getter: () => any, + instance: Component, + id: number, + keys?: any[] +): any { + if (__DEV__ && !Array.isArray(keys)) { + warn( + `keys passed to v-memo or memoize must be an array. Got ${String(keys)}` + ) + } + let storage = memoizeMap.get(instance) + if (!storage) { + storage = [] + memoizeMap.set(instance, storage) + } + const record = storage[id] + if (!record) { + const value = getter() + storage[id] = [value, keys] + return value + } else { + const [prevValue, prevKeys] = record + record[1] = keys + if (keys) { + for (let i = 0; i < keys.length; i++) { + if (keys[i] !== prevKeys[i]) { + return (record[0] = getter()) + } + } + } + return prevValue + } +}