router
router copied to clipboard
View Component unnecessarily updates when child route changes
Version
4.1.6
Reproduction link
Steps to reproduce
- Open linked CodeSandbox
- Observe Console
- 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.
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.
did you try moving the onVnodeUnmounted() outside of the render function to fix the problem? Maybe it just needs that
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.
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
I'll give it a shot tomorrow
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.
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.