Subscribe on changes!

Deriving child vNode props inside render function can be broken by static template optimization.

avatar
Mar 3rd 2021

Version

3.0.7

Reproduction link

https://codesandbox.io/s/strange-tree-1z4i0?file=/src/App.vue:0-2038

image

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.

avatar
Mar 3rd 2021

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.
    ...
}
avatar
Mar 4th 2021

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.

avatar
Mar 4th 2021

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.

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?

avatar
Mar 4th 2021

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.

avatar
Mar 4th 2021

I can get your point, I'm discussing how to solve this kind of needs. I have a two ideas, just hint here:

  1. 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

  1. Provide helper functions, allowing users to use helper functions to modify vnode.props

This doesn’t seem to be user-friendly

avatar
Mar 4th 2021

I can get your point, I'm discussing how to solve this kind of needs. I have a two ideas, just hint here:

  1. 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

  1. 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.

avatar
Jan 5th 2022

I think a helper function that modifies dynamicProps would be fine = =...