feat(core): respect $stable slots flag per RFC

This commit is contained in:
Evan You 2019-11-26 10:03:36 -05:00
parent 009dc80674
commit 43097987cf
3 changed files with 52 additions and 2 deletions

View File

@ -1,3 +1,5 @@
import { h, ref, render, nodeOps, nextTick } from '@vue/runtime-test'
describe('renderer: component', () => {
test.todo('should work')
@ -7,5 +9,47 @@ describe('renderer: component', () => {
test.todo('componentProps')
test.todo('componentSlots')
describe('slots', () => {
test('should respect $stable flag', async () => {
const flag1 = ref(1)
const flag2 = ref(2)
const spy = jest.fn()
const Child = () => {
spy()
return 'child'
}
const App = {
setup() {
return () => [
flag1.value,
h(
Child,
{ n: flag2.value },
{
foo: () => 'foo',
$stable: true
}
)
]
}
}
render(h(App), nodeOps.createElement('div'))
expect(spy).toHaveBeenCalledTimes(1)
// parent re-render, props didn't change, slots are stasble
// -> child should not update
flag1.value++
await nextTick()
expect(spy).toHaveBeenCalledTimes(1)
// parent re-render, props changed
// -> child should update
flag2.value++
await nextTick()
expect(spy).toHaveBeenCalledTimes(2)
})
})
})

View File

@ -138,8 +138,10 @@ export function shouldUpdateComponent(
// this path is only taken by manually written render functions
// so presence of any children leads to a forced update
if (prevChildren != null || nextChildren != null) {
if (nextChildren == null || !(nextChildren as any).$stable) {
return true
}
}
if (prevProps === nextProps) {
return false
}

View File

@ -15,6 +15,9 @@ export type Slots = Readonly<InternalSlots>
export type RawSlots = {
[name: string]: unknown
// manual render fn hint to skip forced children updates
$stable?: boolean
// internal, indicates compiler generated slots = can skip normalization
_compiled?: boolean
}
@ -49,6 +52,7 @@ export function resolveSlots(
} else {
slots = {}
for (const key in rawSlots) {
if (key === '$stable') continue
const value = rawSlots[key]
if (isFunction(value)) {
slots[key] = normalizeSlot(key, value)