refactor: improve functional patch

This commit is contained in:
Evan You 2018-11-13 00:29:18 -05:00
parent fc5aa6d0be
commit f5700245b0

View File

@ -76,10 +76,9 @@ export interface RendererOptions {
} }
export interface FunctionalHandle { export interface FunctionalHandle {
current: VNode prev: VNode
prevTree: VNode next: VNode
runner: Autorun update: Autorun
forceUpdate: () => void
} }
handleSchedulerError(err => handleError(err, null, ErrorTypes.SCHEDULER)) handleSchedulerError(err => handleError(err, null, ErrorTypes.SCHEDULER))
@ -265,27 +264,20 @@ export function createRenderer(options: RendererOptions) {
} }
const handle: FunctionalHandle = (vnode.handle = { const handle: FunctionalHandle = (vnode.handle = {
current: vnode, prev: vnode,
prevTree: null as any, next: null as any,
runner: null as any, update: null as any
forceUpdate: null as any
})
const queueUpdate = (handle.forceUpdate = () => {
queueJob(handle.runner)
}) })
const doMount = () => { const doMount = () => {
handle.runner = autorun( handle.update = autorun(
() => { () => {
if (!handle.prevTree) { if (!handle.next) {
// initial mount // initial mount
if (__DEV__) { if (__DEV__) {
pushWarningContext(vnode) pushWarningContext(vnode)
} }
const subTree = (handle.prevTree = vnode.children = renderFunctionalRoot( const subTree = (vnode.children = renderFunctionalRoot(vnode))
vnode
))
queueEffect(() => { queueEffect(() => {
vnode.el = subTree.el as RenderNode vnode.el = subTree.el as RenderNode
}) })
@ -298,7 +290,7 @@ export function createRenderer(options: RendererOptions) {
} }
}, },
{ {
scheduler: queueUpdate scheduler: queueJob
} }
) )
} }
@ -311,7 +303,7 @@ export function createRenderer(options: RendererOptions) {
doMount() doMount()
// cleanup if mount is invalidated before committed // cleanup if mount is invalidated before committed
return () => { return () => {
stop(handle.runner) stop(handle.update)
} }
}) })
} }
@ -319,21 +311,19 @@ export function createRenderer(options: RendererOptions) {
function updateFunctionalComponent(handle: FunctionalHandle, isSVG: boolean) { function updateFunctionalComponent(handle: FunctionalHandle, isSVG: boolean) {
// mounted // mounted
const { prevTree, current } = handle const { prev, next } = handle
if (__DEV__) { if (__DEV__) {
pushWarningContext(current) pushWarningContext(next)
} }
const nextTree = (handle.prevTree = current.children = renderFunctionalRoot( const nextTree = (next.children = renderFunctionalRoot(next))
current
))
queueEffect(() => { queueEffect(() => {
current.el = nextTree.el next.el = nextTree.el
}) })
patch( patch(
prevTree as MountedVNode, prev.children as MountedVNode,
nextTree, nextTree,
platformParentNode(current.el), platformParentNode(prev.el),
current as MountedVNode, next as MountedVNode,
isSVG isSVG
) )
if (__DEV__) { if (__DEV__) {
@ -618,10 +608,11 @@ export function createRenderer(options: RendererOptions) {
function patchFunctionalComponent(prevVNode: MountedVNode, nextVNode: VNode) { function patchFunctionalComponent(prevVNode: MountedVNode, nextVNode: VNode) {
const prevTree = prevVNode.children as VNode const prevTree = prevVNode.children as VNode
const handle = (nextVNode.handle = prevVNode.handle as FunctionalHandle) const handle = (nextVNode.handle = prevVNode.handle as FunctionalHandle)
handle.current = nextVNode handle.prev = prevVNode
handle.next = nextVNode
if (shouldUpdateComponent(prevVNode, nextVNode)) { if (shouldUpdateComponent(prevVNode, nextVNode)) {
handle.forceUpdate() queueJob(handle.update)
} else if (prevTree.flags & VNodeFlags.COMPONENT) { } else if (prevTree.flags & VNodeFlags.COMPONENT) {
// functional component returned another component // functional component returned another component
prevTree.contextVNode = nextVNode prevTree.contextVNode = nextVNode
@ -1182,7 +1173,7 @@ export function createRenderer(options: RendererOptions) {
} }
} else { } else {
// functional // functional
stop((handle as FunctionalHandle).runner) stop((handle as FunctionalHandle).update)
unmount(children as MountedVNode) unmount(children as MountedVNode)
} }
} else if (flags & VNodeFlags.PORTAL) { } else if (flags & VNodeFlags.PORTAL) {
@ -1293,12 +1284,12 @@ export function createRenderer(options: RendererOptions) {
$options: { beforeMount, renderTracked, renderTriggered } $options: { beforeMount, renderTracked, renderTriggered }
} = instance } = instance
const queueUpdate = (instance.$forceUpdate = () => { instance.$forceUpdate = () => {
queueJob(instance._updateHandle) queueJob(instance._updateHandle)
}) }
const autorunOptions: AutorunOptions = { const autorunOptions: AutorunOptions = {
scheduler: queueUpdate scheduler: queueJob
} }
if (__DEV__) { if (__DEV__) {