router icon indicating copy to clipboard operation
router copied to clipboard

View Component unnecessarily updates when child route changes

Open LinusBorg opened this issue 2 years ago • 9 comments
trafficstars

Version

4.1.6

Reproduction link

codesandbox.io

Steps to reproduce

  1. Open linked CodeSandbox
  2. Observe Console
  3. Click on "Home - A", and then on "Home - B"

What is expected?

Should not log at all, because the component has receives no props and does not depend on any reactive data from the router.

So when a child route changes, it should not update.

What is actually happening?

Home.vue console.logs 3 times, meaning it re-rendered multiple times.


I'm pretty sure the reason for that is that router-view needs to re-render multiple times, and each time, a new onVNodeUnmounted callback is added to the VieComponent vnode's props object here:

https://github.com/vuejs/router/blob/e008551c168ed22c6007577541adf288382103ea/packages/router/src/RouterView.ts#L160-L170

So from the POV of Vue, the props changed. So it will run an update cycle of the router view.

LinusBorg avatar Feb 16 '23 11:02 LinusBorg

Aside from investigating how to fix this in the router, I think we could also look into optimizing this in Vue core. I think the renderer picks the vnode hooks directly from the vnode props when it needs to run them, so changing them should not require any processing/updating of the component itself.

LinusBorg avatar Feb 16 '23 12:02 LinusBorg

did you try moving the onVnodeUnmounted() outside of the render function to fix the problem? Maybe it just needs that

posva avatar Feb 16 '23 13:02 posva

I want to experiment with that, but I see potential problems in as that function has a closure over currentName and matchedRoute, which we would then also have to move out of the render function, and I'm worried we could run into timing issues where these change too fast?

Might not be a problem but needs thorough testing.

Couldn't we also just do that in the watch, though? like, check wether the oldInstance is unmounted (maybe after a tick)? or does that not cover all cases?

Need to test.

LinusBorg avatar Feb 16 '23 13:02 LinusBorg

It's true having the closure avoided timing issues. Having a watcher didn't cover all cases if I remember well but I think I added tests so they should fail if the change is not enough

posva avatar Feb 16 '23 13:02 posva

I'll give it a shot tomorrow

LinusBorg avatar Feb 16 '23 20:02 LinusBorg

I think I found a way of fixing this. It still rerenders when using a <Transition /> component but it looks like a Vue behavior. I need to check that further.

posva avatar Dec 15 '23 09:12 posva

I think I found a way of fixing this. It still rerenders when using a <Transition /> component but it looks like a Vue behavior. I need to check that further.

Did you end up figuring out what was going on here? I have the exact same problem - I have transition "appear" around my RouteView, and always having parents re-render (and re-fetch data) when it's unnecessary.

kirkbushell avatar Apr 19 '24 05:04 kirkbushell