Deriving child vNode props inside render function can be broken by static template optimization.
Version
3.0.7
Reproduction link
https://codesandbox.io/s/strange-tree-1z4i0?file=/src/App.vue:0-2038
Steps to reproduce
Follow the link. I mean to derive some prop before its children do the first rendering. However it won't re-render in a template context.
What is expected?
Re-render should work.
What is actually happening?
Doesn't happening.
should full diff props in updateProps
when patchFlag is PatchFlags.DYNAMIC_SLOTS
?
export function updateProps(
instance: ComponentInternalInstance,
rawProps: Data | null,
rawPrevProps: Data | null,
optimized: boolean
) {
...
if (
// always force full diff in dev
// - #1942 if hmr is enabled with sfc component
// - vite#872 non-sfc component used by sfc component
!(
__DEV__ &&
(instance.type.__hmrId ||
(instance.parent && instance.parent.type.__hmrId))
) &&
(optimized || patchFlag > 0) &&
!(patchFlag & PatchFlags.FULL_PROPS) &&
// add this condition
!(patchFlag & PatchFlags.DYNAMIC_SLOTS)
) {
} else {
// full props update.
...
}
It has nothing to do with slots
, the root cause is that the props
of the GridItem
component will not change from the perspective of the compiler, so it is skipped during runtime diff. Users manually modified the value of props, which is not known to the runtime. As a workground, just add privateShow
to the GridItem
component https://codesandbox.io/s/inspiring-satoshi-b5ws1?file=/src/App.vue .
I think this not only happens with props
, if something needs compiler hints at runtime, it would be dangerous to modify it.
It has nothing to do with
slots
, the root cause is that theprops
of theGridItem
component will not change from the perspective of the compiler, so it is skipped during runtime diff. Users manually modified the value of props, which is not known to the runtime. As a workground, just addprivateShow
to theGridItem
component https://codesandbox.io/s/inspiring-satoshi-b5ws1?file=/src/App.vue .I think this not only happens with
props
, if something needs compiler hints at runtime, it would be dangerous to modify it.
Deriving props is crucial for creating component with advanced features.
For example a responsive grid: User doesn't define which item shows by props. Item to show are derived from props during rendering time. It is a one direction data flow (from parent to child). If you collect data in a reactive field it may cause an infinite rendering loop (since the collected data will be used in render function again).
Is there any option to de-optimize it?
I've thought of another scene in which vNode props can be modified without template props specified.
eg. We have a popover component. It's api looks like:
<popover trigger="hover">
<template #trigger>
<button>show</button>
</template>
Popover content
</popover>
It is a common api pattern.
Event listener will also not be specified.
I can get your point, I'm discussing how to solve this kind of needs. I have a two ideas, just hint here:
- Proxy the
vnode.props
Intercept the user's operations on vnode.props
, so that we can correctly adjust the corresponding patchFlags
and dynamicProps
. But this brings extra VNode creation
and runtime performance consumption
- Provide helper functions, allowing users to use helper functions to modify
vnode.props
This doesn’t seem to be user-friendly
I can get your point, I'm discussing how to solve this kind of needs. I have a two ideas, just hint here:
- Proxy the
vnode.props
Intercept the user's operations on
vnode.props
, so that we can correctly adjust the correspondingpatchFlags
anddynamicProps
. But this brings extraVNode creation
and runtime performance consumption
- Provide helper functions, allowing users to use helper functions to modify
vnode.props
This doesn’t seem to be user-friendly
As a developer I think the first one is more friendly.