fix(hmr): force full update on nested child components (#1312)
This commit is contained in:
parent
4492b88938
commit
8f2a7489b7
@ -218,4 +218,75 @@ describe('hot module replacement', () => {
|
|||||||
rerender(parentId, compileToFunction(`<Child msg="bar" />`))
|
rerender(parentId, compileToFunction(`<Child msg="bar" />`))
|
||||||
expect(serializeInner(root)).toBe(`<div>bar</div>`)
|
expect(serializeInner(root)).toBe(`<div>bar</div>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #1305 - component should remove class
|
||||||
|
test('remove static class from parent', () => {
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
const parentId = 'test-force-class-parent'
|
||||||
|
const childId = 'test-force-class-child'
|
||||||
|
|
||||||
|
const Child: ComponentOptions = {
|
||||||
|
__hmrId: childId,
|
||||||
|
render: compileToFunction(`<div>child</div>`)
|
||||||
|
}
|
||||||
|
createRecord(childId, Child)
|
||||||
|
|
||||||
|
const Parent: ComponentOptions = {
|
||||||
|
__hmrId: parentId,
|
||||||
|
components: { Child },
|
||||||
|
render: compileToFunction(`<Child class="test" />`)
|
||||||
|
}
|
||||||
|
createRecord(parentId, Parent)
|
||||||
|
|
||||||
|
render(h(Parent), root)
|
||||||
|
expect(serializeInner(root)).toBe(`<div class="test">child</div>`)
|
||||||
|
|
||||||
|
rerender(parentId, compileToFunction(`<Child/>`))
|
||||||
|
expect(serializeInner(root)).toBe(`<div>child</div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('rerender if any parent in the parent chain', () => {
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
const parent = 'test-force-props-parent-'
|
||||||
|
const childId = 'test-force-props-child'
|
||||||
|
|
||||||
|
const numberOfParents = 5
|
||||||
|
|
||||||
|
const Child: ComponentOptions = {
|
||||||
|
__hmrId: childId,
|
||||||
|
render: compileToFunction(`<div>child</div>`)
|
||||||
|
}
|
||||||
|
createRecord(childId, Child)
|
||||||
|
|
||||||
|
const components: ComponentOptions[] = []
|
||||||
|
|
||||||
|
for (let i = 0; i < numberOfParents; i++) {
|
||||||
|
const parentId = `${parent}${i}`
|
||||||
|
const parentComp: ComponentOptions = {
|
||||||
|
__hmrId: parentId
|
||||||
|
}
|
||||||
|
components.push(parentComp)
|
||||||
|
if (i === 0) {
|
||||||
|
parentComp.render = compileToFunction(`<Child />`)
|
||||||
|
parentComp.components = {
|
||||||
|
Child
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parentComp.render = compileToFunction(`<Parent />`)
|
||||||
|
parentComp.components = {
|
||||||
|
Parent: components[i - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createRecord(parentId, parentComp)
|
||||||
|
}
|
||||||
|
|
||||||
|
const last = components[components.length - 1]
|
||||||
|
|
||||||
|
render(h(last), root)
|
||||||
|
expect(serializeInner(root)).toBe(`<div>child</div>`)
|
||||||
|
|
||||||
|
rerender(last.__hmrId!, compileToFunction(`<Parent class="test"/>`))
|
||||||
|
expect(serializeInner(root)).toBe(`<div class="test">child</div>`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -247,14 +247,14 @@ export function shouldUpdateComponent(
|
|||||||
// Parent component's render function was hot-updated. Since this may have
|
// Parent component's render function was hot-updated. Since this may have
|
||||||
// caused the child component's slots content to have changed, we need to
|
// caused the child component's slots content to have changed, we need to
|
||||||
// force the child to update as well.
|
// force the child to update as well.
|
||||||
if (
|
if (__DEV__ && (prevChildren || nextChildren) && parentComponent) {
|
||||||
__DEV__ &&
|
let parent: ComponentInternalInstance | null = parentComponent
|
||||||
(prevChildren || nextChildren) &&
|
do {
|
||||||
parentComponent &&
|
if (parent.hmrUpdated) {
|
||||||
parentComponent.hmrUpdated
|
|
||||||
) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
} while ((parent = parent.parent))
|
||||||
|
}
|
||||||
|
|
||||||
// force child update for runtime directive or transition on component vnode.
|
// force child update for runtime directive or transition on component vnode.
|
||||||
if (nextVNode.dirs || nextVNode.transition) {
|
if (nextVNode.dirs || nextVNode.transition) {
|
||||||
@ -268,8 +268,11 @@ export function shouldUpdateComponent(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (patchFlag & PatchFlags.FULL_PROPS) {
|
if (patchFlag & PatchFlags.FULL_PROPS) {
|
||||||
|
if (!prevProps) {
|
||||||
|
return !!nextProps
|
||||||
|
}
|
||||||
// presence of this flag indicates props are always non-null
|
// presence of this flag indicates props are always non-null
|
||||||
return hasPropsChanged(prevProps!, nextProps!)
|
return hasPropsChanged(prevProps, nextProps!)
|
||||||
} else if (patchFlag & PatchFlags.PROPS) {
|
} else if (patchFlag & PatchFlags.PROPS) {
|
||||||
const dynamicProps = nextVNode.dynamicProps!
|
const dynamicProps = nextVNode.dynamicProps!
|
||||||
for (let i = 0; i < dynamicProps.length; i++) {
|
for (let i = 0; i < dynamicProps.length; i++) {
|
||||||
|
@ -791,11 +791,18 @@ function baseCreateRenderer(
|
|||||||
invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate')
|
invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__DEV__ && parentComponent && parentComponent.hmrUpdated) {
|
// check if any component of the parent chain has `hmrUpdated`
|
||||||
|
if (__DEV__ && parentComponent) {
|
||||||
|
let parent: ComponentInternalInstance | null = parentComponent
|
||||||
|
do {
|
||||||
|
if (parent.hmrUpdated) {
|
||||||
// HMR updated, force full diff
|
// HMR updated, force full diff
|
||||||
patchFlag = 0
|
patchFlag = 0
|
||||||
optimized = false
|
optimized = false
|
||||||
dynamicChildren = null
|
dynamicChildren = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} while ((parent = parent.parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patchFlag > 0) {
|
if (patchFlag > 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user