useRouter().* vs Router.* - when to use for best performance #67520
Unanswered
alex-statsig
asked this question in
Help
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Summary
I've noticed in my app that many components need to re-render on "route changes" because they use
useRouter()
, despite not actually caring about the route change. This is because they oftenuseRouter()
purely for a click handler or mutation-basedrouter.push(...)
, or perhaps logging therouter.pathname
in some instrumentation on click. This can happen in components shared across page changes (Ex. a header bar that always remains mounted) or when query params change (ex. if filters are encoded into the URL, not much about the page changes but everyuseRouter
has to rerender).I've realized that by importing the static
Router
(import Router from 'next-router'
), I can avoid this re-render and still properly access any router properties (ex. Router.pathname, Router.push) with the correct values in a click handler.However, if I do want to access Router properties during render (whether initial render only, or subscribing for subsequent renders), I need to use
useRouter
to ensure the proper router properties are used during route transitions (in which the global Router may not be updated yet, and the component will not subscribe to further updates).I wanted to get people's opinions on how they use
useRouter
vs staticRouter
. Is it good practice to only useuseRouter
if you need the router in render, and otherwise useRouter
? This seems to work the best for me, but the documentation shows otherwise in numerous places. I can't find references / guide to the static Router really. Even the built-in link component usesuseRouter
despite not caring about query parameter changes (it only seems to need some static metadata from it), leading to any buttons/links re-rendering excessively.The only danger I see of using the static Router (but perhaps I've missed something) is the risk of someone using the already-imported
Router.*
in render (ex. I createMyButton
, loggingRouter.pathname
on click; someone else modifiesMyButton
and decides to change the button color based onRouter.pathname
; this won't work properly mid-transition, and won't trigger a rerender if the pathname changes, they need to add auseRouter()
). Generally its also nice to load values from context instead of global namespace, so a hook likeuseRouterStatic
might be cleaner (although I doubt anyone will have multiple nextjs router providers at once).Additional information
Note: I'm using the pages directory currently, but as far as I can tell these tradeoffs apply to the app router as well.
Example
No response
Beta Was this translation helpful? Give feedback.
All reactions