test: more tests for keep-alive
This commit is contained in:
parent
5fcb81050a
commit
4631f5323b
@ -9,15 +9,18 @@ import {
|
|||||||
serializeInner,
|
serializeInner,
|
||||||
nextTick
|
nextTick
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
|
import { KeepAliveProps } from '../src/keepAlive'
|
||||||
|
|
||||||
describe('keep-alive', () => {
|
describe('keep-alive', () => {
|
||||||
let one: ComponentOptions
|
let one: ComponentOptions
|
||||||
let two: ComponentOptions
|
let two: ComponentOptions
|
||||||
|
let views: Record<string, ComponentOptions>
|
||||||
let root: TestElement
|
let root: TestElement
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
root = nodeOps.createElement('div')
|
root = nodeOps.createElement('div')
|
||||||
one = {
|
one = {
|
||||||
|
name: 'one',
|
||||||
data: () => ({ msg: 'one' }),
|
data: () => ({ msg: 'one' }),
|
||||||
render() {
|
render() {
|
||||||
return h('div', this.msg)
|
return h('div', this.msg)
|
||||||
@ -29,6 +32,7 @@ describe('keep-alive', () => {
|
|||||||
unmounted: jest.fn()
|
unmounted: jest.fn()
|
||||||
}
|
}
|
||||||
two = {
|
two = {
|
||||||
|
name: 'two',
|
||||||
data: () => ({ msg: 'two' }),
|
data: () => ({ msg: 'two' }),
|
||||||
render() {
|
render() {
|
||||||
return h('div', this.msg)
|
return h('div', this.msg)
|
||||||
@ -39,6 +43,10 @@ describe('keep-alive', () => {
|
|||||||
deactivated: jest.fn(),
|
deactivated: jest.fn(),
|
||||||
unmounted: jest.fn()
|
unmounted: jest.fn()
|
||||||
}
|
}
|
||||||
|
views = {
|
||||||
|
one,
|
||||||
|
two
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function assertHookCalls(component: any, callCounts: number[]) {
|
function assertHookCalls(component: any, callCounts: number[]) {
|
||||||
@ -52,12 +60,12 @@ describe('keep-alive', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test('should preserve state', async () => {
|
test('should preserve state', async () => {
|
||||||
const toggle = ref(true)
|
const viewRef = ref('one')
|
||||||
const instanceRef = ref<any>(null)
|
const instanceRef = ref<any>(null)
|
||||||
const App = {
|
const App = {
|
||||||
render() {
|
render() {
|
||||||
return h(KeepAlive, null, {
|
return h(KeepAlive, null, {
|
||||||
default: () => h(toggle.value ? one : two, { ref: instanceRef })
|
default: () => h(views[viewRef.value], { ref: instanceRef })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,22 +74,20 @@ describe('keep-alive', () => {
|
|||||||
instanceRef.value.msg = 'changed'
|
instanceRef.value.msg = 'changed'
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(serializeInner(root)).toBe(`<div>changed</div>`)
|
expect(serializeInner(root)).toBe(`<div>changed</div>`)
|
||||||
toggle.value = false
|
viewRef.value = 'two'
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(serializeInner(root)).toBe(`<div>two</div>`)
|
expect(serializeInner(root)).toBe(`<div>two</div>`)
|
||||||
toggle.value = true
|
viewRef.value = 'one'
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(serializeInner(root)).toBe(`<div>changed</div>`)
|
expect(serializeInner(root)).toBe(`<div>changed</div>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should call correct lifecycle hooks', async () => {
|
test('should call correct lifecycle hooks', async () => {
|
||||||
const toggle1 = ref(true)
|
const toggle = ref(true)
|
||||||
const toggle2 = ref(true)
|
const viewRef = ref('one')
|
||||||
const App = {
|
const App = {
|
||||||
render() {
|
render() {
|
||||||
return toggle1.value
|
return toggle.value ? h(KeepAlive, () => h(views[viewRef.value])) : null
|
||||||
? h(KeepAlive, () => h(toggle2.value ? one : two))
|
|
||||||
: null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render(h(App), root)
|
render(h(App), root)
|
||||||
@ -91,26 +97,26 @@ describe('keep-alive', () => {
|
|||||||
assertHookCalls(two, [0, 0, 0, 0, 0])
|
assertHookCalls(two, [0, 0, 0, 0, 0])
|
||||||
|
|
||||||
// toggle kept-alive component
|
// toggle kept-alive component
|
||||||
toggle2.value = false
|
viewRef.value = 'two'
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(serializeInner(root)).toBe(`<div>two</div>`)
|
expect(serializeInner(root)).toBe(`<div>two</div>`)
|
||||||
assertHookCalls(one, [1, 1, 1, 1, 0])
|
assertHookCalls(one, [1, 1, 1, 1, 0])
|
||||||
assertHookCalls(two, [1, 1, 1, 0, 0])
|
assertHookCalls(two, [1, 1, 1, 0, 0])
|
||||||
|
|
||||||
toggle2.value = true
|
viewRef.value = 'one'
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(serializeInner(root)).toBe(`<div>one</div>`)
|
expect(serializeInner(root)).toBe(`<div>one</div>`)
|
||||||
assertHookCalls(one, [1, 1, 2, 1, 0])
|
assertHookCalls(one, [1, 1, 2, 1, 0])
|
||||||
assertHookCalls(two, [1, 1, 1, 1, 0])
|
assertHookCalls(two, [1, 1, 1, 1, 0])
|
||||||
|
|
||||||
toggle2.value = false
|
viewRef.value = 'two'
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(serializeInner(root)).toBe(`<div>two</div>`)
|
expect(serializeInner(root)).toBe(`<div>two</div>`)
|
||||||
assertHookCalls(one, [1, 1, 2, 2, 0])
|
assertHookCalls(one, [1, 1, 2, 2, 0])
|
||||||
assertHookCalls(two, [1, 1, 2, 1, 0])
|
assertHookCalls(two, [1, 1, 2, 1, 0])
|
||||||
|
|
||||||
// teardown keep-alive, should unmount all components including cached
|
// teardown keep-alive, should unmount all components including cached
|
||||||
toggle1.value = false
|
toggle.value = false
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(serializeInner(root)).toBe(`<!---->`)
|
expect(serializeInner(root)).toBe(`<!---->`)
|
||||||
assertHookCalls(one, [1, 1, 2, 2, 1])
|
assertHookCalls(one, [1, 1, 2, 2, 1])
|
||||||
@ -230,4 +236,300 @@ describe('keep-alive', () => {
|
|||||||
assertHookCalls(one, [1, 1, 4, 3, 0])
|
assertHookCalls(one, [1, 1, 4, 3, 0])
|
||||||
assertHookCalls(two, [1, 1, 4, 4, 0]) // should remain inactive
|
assertHookCalls(two, [1, 1, 4, 4, 0]) // should remain inactive
|
||||||
})
|
})
|
||||||
|
|
||||||
|
async function assertNameMatch(props: KeepAliveProps) {
|
||||||
|
const outerRef = ref(true)
|
||||||
|
const viewRef = ref('one')
|
||||||
|
const App = {
|
||||||
|
render() {
|
||||||
|
return outerRef.value
|
||||||
|
? h(KeepAlive, props, () => h(views[viewRef.value]))
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render(h(App), root)
|
||||||
|
|
||||||
|
expect(serializeInner(root)).toBe(`<div>one</div>`)
|
||||||
|
assertHookCalls(one, [1, 1, 1, 0, 0])
|
||||||
|
assertHookCalls(two, [0, 0, 0, 0, 0])
|
||||||
|
|
||||||
|
viewRef.value = 'two'
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>two</div>`)
|
||||||
|
assertHookCalls(one, [1, 1, 1, 1, 0])
|
||||||
|
assertHookCalls(two, [1, 1, 0, 0, 0])
|
||||||
|
|
||||||
|
viewRef.value = 'one'
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>one</div>`)
|
||||||
|
assertHookCalls(one, [1, 1, 2, 1, 0])
|
||||||
|
assertHookCalls(two, [1, 1, 0, 0, 1])
|
||||||
|
|
||||||
|
viewRef.value = 'two'
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>two</div>`)
|
||||||
|
assertHookCalls(one, [1, 1, 2, 2, 0])
|
||||||
|
assertHookCalls(two, [2, 2, 0, 0, 1])
|
||||||
|
|
||||||
|
// teardown
|
||||||
|
outerRef.value = false
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<!---->`)
|
||||||
|
assertHookCalls(one, [1, 1, 2, 2, 1])
|
||||||
|
assertHookCalls(two, [2, 2, 0, 0, 2])
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('props', () => {
|
||||||
|
test('include (string)', async () => {
|
||||||
|
await assertNameMatch({ include: 'one' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('include (regex)', async () => {
|
||||||
|
await assertNameMatch({ include: /^one$/ })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('include (array)', async () => {
|
||||||
|
await assertNameMatch({ include: ['one'] })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('exclude (string)', async () => {
|
||||||
|
await assertNameMatch({ exclude: 'two' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('exclude (regex)', async () => {
|
||||||
|
await assertNameMatch({ exclude: /^two$/ })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('exclude (array)', async () => {
|
||||||
|
await assertNameMatch({ exclude: ['two'] })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('include + exclude', async () => {
|
||||||
|
await assertNameMatch({ include: 'one,two', exclude: 'two' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('max', async () => {
|
||||||
|
const spyA = jest.fn()
|
||||||
|
const spyB = jest.fn()
|
||||||
|
const spyC = jest.fn()
|
||||||
|
const spyAD = jest.fn()
|
||||||
|
const spyBD = jest.fn()
|
||||||
|
const spyCD = jest.fn()
|
||||||
|
|
||||||
|
function assertCount(calls: number[]) {
|
||||||
|
expect([
|
||||||
|
spyA.mock.calls.length,
|
||||||
|
spyAD.mock.calls.length,
|
||||||
|
spyB.mock.calls.length,
|
||||||
|
spyBD.mock.calls.length,
|
||||||
|
spyC.mock.calls.length,
|
||||||
|
spyCD.mock.calls.length
|
||||||
|
]).toEqual(calls)
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewRef = ref('a')
|
||||||
|
const views: Record<string, ComponentOptions> = {
|
||||||
|
a: {
|
||||||
|
render: () => `one`,
|
||||||
|
created: spyA,
|
||||||
|
unmounted: spyAD
|
||||||
|
},
|
||||||
|
b: {
|
||||||
|
render: () => `two`,
|
||||||
|
created: spyB,
|
||||||
|
unmounted: spyBD
|
||||||
|
},
|
||||||
|
c: {
|
||||||
|
render: () => `three`,
|
||||||
|
created: spyC,
|
||||||
|
unmounted: spyCD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
render() {
|
||||||
|
return h(KeepAlive, { max: 2 }, () => {
|
||||||
|
return h(views[viewRef.value])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render(h(App), root)
|
||||||
|
assertCount([1, 0, 0, 0, 0, 0])
|
||||||
|
|
||||||
|
viewRef.value = 'b'
|
||||||
|
await nextTick()
|
||||||
|
assertCount([1, 0, 1, 0, 0, 0])
|
||||||
|
|
||||||
|
viewRef.value = 'c'
|
||||||
|
await nextTick()
|
||||||
|
// should prune A because max cache reached
|
||||||
|
assertCount([1, 1, 1, 0, 1, 0])
|
||||||
|
|
||||||
|
viewRef.value = 'b'
|
||||||
|
await nextTick()
|
||||||
|
// B should be reused, and made latest
|
||||||
|
assertCount([1, 1, 1, 0, 1, 0])
|
||||||
|
|
||||||
|
viewRef.value = 'a'
|
||||||
|
await nextTick()
|
||||||
|
// C should be pruned because B was used last so C is the oldest cached
|
||||||
|
assertCount([2, 1, 1, 0, 1, 1])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('cache invalidation', () => {
|
||||||
|
function setup() {
|
||||||
|
const viewRef = ref('one')
|
||||||
|
const includeRef = ref('one,two')
|
||||||
|
const App = {
|
||||||
|
render() {
|
||||||
|
return h(
|
||||||
|
KeepAlive,
|
||||||
|
{
|
||||||
|
include: includeRef.value
|
||||||
|
},
|
||||||
|
() => h(views[viewRef.value])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render(h(App), root)
|
||||||
|
return { viewRef, includeRef }
|
||||||
|
}
|
||||||
|
|
||||||
|
test('on include/exclude change', async () => {
|
||||||
|
const { viewRef, includeRef } = setup()
|
||||||
|
|
||||||
|
viewRef.value = 'two'
|
||||||
|
await nextTick()
|
||||||
|
assertHookCalls(one, [1, 1, 1, 1, 0])
|
||||||
|
assertHookCalls(two, [1, 1, 1, 0, 0])
|
||||||
|
|
||||||
|
includeRef.value = 'two'
|
||||||
|
await nextTick()
|
||||||
|
assertHookCalls(one, [1, 1, 1, 1, 1])
|
||||||
|
assertHookCalls(two, [1, 1, 1, 0, 0])
|
||||||
|
|
||||||
|
viewRef.value = 'one'
|
||||||
|
await nextTick()
|
||||||
|
assertHookCalls(one, [2, 2, 1, 1, 1])
|
||||||
|
assertHookCalls(two, [1, 1, 1, 1, 0])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('on include/exclude change + view switch', async () => {
|
||||||
|
const { viewRef, includeRef } = setup()
|
||||||
|
|
||||||
|
viewRef.value = 'two'
|
||||||
|
await nextTick()
|
||||||
|
assertHookCalls(one, [1, 1, 1, 1, 0])
|
||||||
|
assertHookCalls(two, [1, 1, 1, 0, 0])
|
||||||
|
|
||||||
|
includeRef.value = 'one'
|
||||||
|
viewRef.value = 'one'
|
||||||
|
await nextTick()
|
||||||
|
assertHookCalls(one, [1, 1, 2, 1, 0])
|
||||||
|
// two should be pruned
|
||||||
|
assertHookCalls(two, [1, 1, 1, 1, 1])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should not prune current active instance', async () => {
|
||||||
|
const { viewRef, includeRef } = setup()
|
||||||
|
|
||||||
|
includeRef.value = 'two'
|
||||||
|
await nextTick()
|
||||||
|
assertHookCalls(one, [1, 1, 1, 0, 0])
|
||||||
|
assertHookCalls(two, [0, 0, 0, 0, 0])
|
||||||
|
|
||||||
|
viewRef.value = 'two'
|
||||||
|
await nextTick()
|
||||||
|
assertHookCalls(one, [1, 1, 1, 0, 1])
|
||||||
|
assertHookCalls(two, [1, 1, 1, 0, 0])
|
||||||
|
})
|
||||||
|
|
||||||
|
async function assertAnonymous(include: boolean) {
|
||||||
|
const one = {
|
||||||
|
name: 'one',
|
||||||
|
created: jest.fn(),
|
||||||
|
render: () => 'one'
|
||||||
|
}
|
||||||
|
|
||||||
|
const two = {
|
||||||
|
// anonymous
|
||||||
|
created: jest.fn(),
|
||||||
|
render: () => 'two'
|
||||||
|
}
|
||||||
|
|
||||||
|
const views: any = { one, two }
|
||||||
|
const viewRef = ref('one')
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
render() {
|
||||||
|
return h(
|
||||||
|
KeepAlive,
|
||||||
|
{
|
||||||
|
include: include ? 'one' : undefined
|
||||||
|
},
|
||||||
|
() => h(views[viewRef.value])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render(h(App), root)
|
||||||
|
|
||||||
|
function assert(oneCreateCount: number, twoCreateCount: number) {
|
||||||
|
expect(one.created.mock.calls.length).toBe(oneCreateCount)
|
||||||
|
expect(two.created.mock.calls.length).toBe(twoCreateCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(1, 0)
|
||||||
|
|
||||||
|
viewRef.value = 'two'
|
||||||
|
await nextTick()
|
||||||
|
assert(1, 1)
|
||||||
|
|
||||||
|
viewRef.value = 'one'
|
||||||
|
await nextTick()
|
||||||
|
assert(1, 1)
|
||||||
|
|
||||||
|
viewRef.value = 'two'
|
||||||
|
await nextTick()
|
||||||
|
// two should be re-created if include is specified, since it's not matched
|
||||||
|
// otherwise it should be cached.
|
||||||
|
assert(1, include ? 2 : 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.x #6938
|
||||||
|
test('should not cache anonymous component when include is specified', async () => {
|
||||||
|
await assertAnonymous(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should cache anonymous components if include is not specified', async () => {
|
||||||
|
await assertAnonymous(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 2.x #7105
|
||||||
|
test('should not destroy active instance when pruning cache', async () => {
|
||||||
|
const Foo = {
|
||||||
|
render: () => 'foo',
|
||||||
|
unmounted: jest.fn()
|
||||||
|
}
|
||||||
|
const includeRef = ref(['foo'])
|
||||||
|
const App = {
|
||||||
|
render() {
|
||||||
|
return h(
|
||||||
|
KeepAlive,
|
||||||
|
{
|
||||||
|
include: includeRef.value
|
||||||
|
},
|
||||||
|
() => h(Foo)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render(h(App), root)
|
||||||
|
// condition: a render where a previous component is reused
|
||||||
|
includeRef.value = ['foo', 'bar']
|
||||||
|
await nextTick()
|
||||||
|
includeRef.value = []
|
||||||
|
await nextTick()
|
||||||
|
expect(Foo.unmounted).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -901,7 +901,11 @@ export function createRenderer<
|
|||||||
queuePostRenderEffect(instance.m, parentSuspense)
|
queuePostRenderEffect(instance.m, parentSuspense)
|
||||||
}
|
}
|
||||||
// activated hook for keep-alive roots.
|
// activated hook for keep-alive roots.
|
||||||
if (instance.a !== null) {
|
if (
|
||||||
|
instance.a !== null &&
|
||||||
|
instance.vnode.shapeFlag &
|
||||||
|
ShapeFlags.STATEFUL_COMPONENT_SHOULD_KEEP_ALIVE
|
||||||
|
) {
|
||||||
queuePostRenderEffect(instance.a, parentSuspense)
|
queuePostRenderEffect(instance.a, parentSuspense)
|
||||||
}
|
}
|
||||||
mounted = true
|
mounted = true
|
||||||
@ -1477,7 +1481,11 @@ export function createRenderer<
|
|||||||
queuePostRenderEffect(um, parentSuspense)
|
queuePostRenderEffect(um, parentSuspense)
|
||||||
}
|
}
|
||||||
// deactivated hook
|
// deactivated hook
|
||||||
if (da !== null && !isDeactivated) {
|
if (
|
||||||
|
da !== null &&
|
||||||
|
!isDeactivated &&
|
||||||
|
instance.vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT_SHOULD_KEEP_ALIVE
|
||||||
|
) {
|
||||||
queuePostRenderEffect(da, parentSuspense)
|
queuePostRenderEffect(da, parentSuspense)
|
||||||
}
|
}
|
||||||
queuePostFlushCb(() => {
|
queuePostFlushCb(() => {
|
||||||
|
@ -22,7 +22,7 @@ import {
|
|||||||
|
|
||||||
type MatchPattern = string | RegExp | string[] | RegExp[]
|
type MatchPattern = string | RegExp | string[] | RegExp[]
|
||||||
|
|
||||||
interface KeepAliveProps {
|
export interface KeepAliveProps {
|
||||||
include?: MatchPattern
|
include?: MatchPattern
|
||||||
exclude?: MatchPattern
|
exclude?: MatchPattern
|
||||||
max?: number | string
|
max?: number | string
|
||||||
@ -62,16 +62,22 @@ export const KeepAlive = {
|
|||||||
sink.activate = (vnode, container, anchor) => {
|
sink.activate = (vnode, container, anchor) => {
|
||||||
move(vnode, container, anchor)
|
move(vnode, container, anchor)
|
||||||
queuePostRenderEffect(() => {
|
queuePostRenderEffect(() => {
|
||||||
vnode.component!.isDeactivated = false
|
const component = vnode.component!
|
||||||
invokeHooks(vnode.component!.a!)
|
component.isDeactivated = false
|
||||||
|
if (component.a !== null) {
|
||||||
|
invokeHooks(component.a)
|
||||||
|
}
|
||||||
}, parentSuspense)
|
}, parentSuspense)
|
||||||
}
|
}
|
||||||
|
|
||||||
sink.deactivate = (vnode: VNode) => {
|
sink.deactivate = (vnode: VNode) => {
|
||||||
move(vnode, storageContainer, null)
|
move(vnode, storageContainer, null)
|
||||||
queuePostRenderEffect(() => {
|
queuePostRenderEffect(() => {
|
||||||
invokeHooks(vnode.component!.da!)
|
const component = vnode.component!
|
||||||
vnode.component!.isDeactivated = true
|
if (component.da !== null) {
|
||||||
|
invokeHooks(component.da)
|
||||||
|
}
|
||||||
|
component.isDeactivated = true
|
||||||
}, parentSuspense)
|
}, parentSuspense)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +100,10 @@ export const KeepAlive = {
|
|||||||
const cached = cache.get(key) as VNode
|
const cached = cache.get(key) as VNode
|
||||||
if (!current || cached.type !== current.type) {
|
if (!current || cached.type !== current.type) {
|
||||||
unmount(cached)
|
unmount(cached)
|
||||||
|
} else if (current) {
|
||||||
|
// current active instance should no longer be kept-alive.
|
||||||
|
// we can't unmount it now but it might be later, so reset its flag now.
|
||||||
|
current.shapeFlag = ShapeFlags.STATEFUL_COMPONENT
|
||||||
}
|
}
|
||||||
cache.delete(key)
|
cache.delete(key)
|
||||||
keys.delete(key)
|
keys.delete(key)
|
||||||
|
Loading…
Reference in New Issue
Block a user