feat(core): respect $stable slots flag per RFC
This commit is contained in:
parent
009dc80674
commit
43097987cf
@ -1,3 +1,5 @@
|
|||||||
|
import { h, ref, render, nodeOps, nextTick } from '@vue/runtime-test'
|
||||||
|
|
||||||
describe('renderer: component', () => {
|
describe('renderer: component', () => {
|
||||||
test.todo('should work')
|
test.todo('should work')
|
||||||
|
|
||||||
@ -7,5 +9,47 @@ describe('renderer: component', () => {
|
|||||||
|
|
||||||
test.todo('componentProps')
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -138,7 +138,9 @@ export function shouldUpdateComponent(
|
|||||||
// this path is only taken by manually written render functions
|
// this path is only taken by manually written render functions
|
||||||
// so presence of any children leads to a forced update
|
// so presence of any children leads to a forced update
|
||||||
if (prevChildren != null || nextChildren != null) {
|
if (prevChildren != null || nextChildren != null) {
|
||||||
return true
|
if (nextChildren == null || !(nextChildren as any).$stable) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (prevProps === nextProps) {
|
if (prevProps === nextProps) {
|
||||||
return false
|
return false
|
||||||
|
@ -15,6 +15,9 @@ export type Slots = Readonly<InternalSlots>
|
|||||||
|
|
||||||
export type RawSlots = {
|
export type RawSlots = {
|
||||||
[name: string]: unknown
|
[name: string]: unknown
|
||||||
|
// manual render fn hint to skip forced children updates
|
||||||
|
$stable?: boolean
|
||||||
|
// internal, indicates compiler generated slots = can skip normalization
|
||||||
_compiled?: boolean
|
_compiled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,6 +52,7 @@ export function resolveSlots(
|
|||||||
} else {
|
} else {
|
||||||
slots = {}
|
slots = {}
|
||||||
for (const key in rawSlots) {
|
for (const key in rawSlots) {
|
||||||
|
if (key === '$stable') continue
|
||||||
const value = rawSlots[key]
|
const value = rawSlots[key]
|
||||||
if (isFunction(value)) {
|
if (isFunction(value)) {
|
||||||
slots[key] = normalizeSlot(key, value)
|
slots[key] = normalizeSlot(key, value)
|
||||||
|
Loading…
Reference in New Issue
Block a user