fix(keep-alive): fix unmounting late-included components
fix #3648 based on #3650
This commit is contained in:
		
							parent
							
								
									20ed16f68c
								
							
						
					
					
						commit
						da49c863a2
					
				@ -18,7 +18,12 @@ import {
 | 
			
		||||
  defineAsyncComponent,
 | 
			
		||||
  Component,
 | 
			
		||||
  createApp,
 | 
			
		||||
  onActivated
 | 
			
		||||
  onActivated,
 | 
			
		||||
  onUnmounted,
 | 
			
		||||
  onMounted,
 | 
			
		||||
  reactive,
 | 
			
		||||
  shallowRef,
 | 
			
		||||
  onDeactivated
 | 
			
		||||
} from '@vue/runtime-test'
 | 
			
		||||
import { KeepAliveProps } from '../../src/components/KeepAlive'
 | 
			
		||||
 | 
			
		||||
@ -903,4 +908,73 @@ describe('KeepAlive', () => {
 | 
			
		||||
    await nextTick()
 | 
			
		||||
    expect(handler).toHaveBeenCalledWith(err, {}, 'activated hook')
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // #3648
 | 
			
		||||
  test('should avoid unmount later included components', async () => {
 | 
			
		||||
    const unmountedA = jest.fn()
 | 
			
		||||
    const mountedA = jest.fn()
 | 
			
		||||
    const activatedA = jest.fn()
 | 
			
		||||
    const deactivatedA = jest.fn()
 | 
			
		||||
    const unmountedB = jest.fn()
 | 
			
		||||
    const mountedB = jest.fn()
 | 
			
		||||
 | 
			
		||||
    const A = {
 | 
			
		||||
      name: 'A',
 | 
			
		||||
      setup() {
 | 
			
		||||
        onMounted(mountedA)
 | 
			
		||||
        onUnmounted(unmountedA)
 | 
			
		||||
        onActivated(activatedA)
 | 
			
		||||
        onDeactivated(deactivatedA)
 | 
			
		||||
        return () => 'A'
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    const B = {
 | 
			
		||||
      name: 'B',
 | 
			
		||||
      setup() {
 | 
			
		||||
        onMounted(mountedB)
 | 
			
		||||
        onUnmounted(unmountedB)
 | 
			
		||||
        return () => 'B'
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const include = reactive<string[]>([])
 | 
			
		||||
    const current = shallowRef(A)
 | 
			
		||||
    const app = createApp({
 | 
			
		||||
      setup() {
 | 
			
		||||
        return () => {
 | 
			
		||||
          return [
 | 
			
		||||
            h(
 | 
			
		||||
              KeepAlive,
 | 
			
		||||
              {
 | 
			
		||||
                include
 | 
			
		||||
              },
 | 
			
		||||
              h(current.value)
 | 
			
		||||
            )
 | 
			
		||||
          ]
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    app.mount(root)
 | 
			
		||||
 | 
			
		||||
    expect(serializeInner(root)).toBe(`A`)
 | 
			
		||||
    expect(mountedA).toHaveBeenCalledTimes(1)
 | 
			
		||||
    expect(unmountedA).toHaveBeenCalledTimes(0)
 | 
			
		||||
    expect(activatedA).toHaveBeenCalledTimes(0)
 | 
			
		||||
    expect(deactivatedA).toHaveBeenCalledTimes(0)
 | 
			
		||||
    expect(mountedB).toHaveBeenCalledTimes(0)
 | 
			
		||||
    expect(unmountedB).toHaveBeenCalledTimes(0)
 | 
			
		||||
 | 
			
		||||
    include.push('A') // cache A
 | 
			
		||||
    await nextTick()
 | 
			
		||||
    current.value = B // toggle to B
 | 
			
		||||
    await nextTick()
 | 
			
		||||
    expect(serializeInner(root)).toBe(`B`)
 | 
			
		||||
    expect(mountedA).toHaveBeenCalledTimes(1)
 | 
			
		||||
    expect(unmountedA).toHaveBeenCalledTimes(0)
 | 
			
		||||
    expect(activatedA).toHaveBeenCalledTimes(0)
 | 
			
		||||
    expect(deactivatedA).toHaveBeenCalledTimes(1)
 | 
			
		||||
    expect(mountedB).toHaveBeenCalledTimes(1)
 | 
			
		||||
    expect(unmountedB).toHaveBeenCalledTimes(0)
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@ -42,6 +42,7 @@ import { setTransitionHooks } from './BaseTransition'
 | 
			
		||||
import { ComponentRenderContext } from '../componentPublicInstance'
 | 
			
		||||
import { devtoolsComponentAdded } from '../devtools'
 | 
			
		||||
import { isAsyncWrapper } from '../apiAsyncComponent'
 | 
			
		||||
import { isSuspense } from './Suspense'
 | 
			
		||||
 | 
			
		||||
type MatchPattern = string | RegExp | (string | RegExp)[]
 | 
			
		||||
 | 
			
		||||
@ -323,7 +324,7 @@ const KeepAliveImpl: ComponentOptions = {
 | 
			
		||||
      vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
 | 
			
		||||
 | 
			
		||||
      current = vnode
 | 
			
		||||
      return rawVNode
 | 
			
		||||
      return isSuspense(rawVNode.type) ? rawVNode : vnode
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user