New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Performance concerns on RouterContext with useHistory. #6999
Comments
Looking into this briefly (not to familiar with the codebase yet): it seems it would be beneficial to use React 16 as a peer dep now. I notice that in the context file it is pulling from that is created, it's simply creating the context without regard to Provider -- also using an older polyfill for context. If we bump to React 16, we can just As a side effect, this would also cut bundle size just slightly which is nice as If I have some time later on in the day today, would definitely like to try to open a PR on that. |
@rob2d The story goes like this: we are still supporting React versions without support for Now for the actual problem: we pass all of our api details via the react context. Therefore any change will cause a re-rendering and the use of |
In reference to #7000 |
Maybe one of the three options might help you guys: facebook/react#15156 (comment) (option 1 is kind of the solution used by @esealcode) |
I tried to split contexts like @esealcode and to completely disconnect url change via history.push() from any other components / render. It basically just pushes a new random url by pressing a key, with its own context, and the animation slows down exactly at this moment. It seems that the only action of mutating history causes a framerate drop (animation are made via react-spring / request animation frame). |
I can see the reasoning for maintaining backwards compat and usually pretty sensible. Just IMHO but it seems like supporting React < 16 in new releases might be a little bit overkill when increasing package size/lib complexity for everyone else. There's been a warning that context has been experimental since pre 16 I believe (which spans back > 2 years), and official Context API was released about 20 months ago initially in prod [also trust me I understand that time flies; it's hard to realize it's already been that long!]. For the main issue, completely makes sense. It could work to provide context a bit separate as that is sort of already provided optionally via 3rd party, so it's not entirely out-there to decouple that from the rest as that idea is somewhat consistent when considering the possible use cases of history itself. Aside from this, functionality with history could be deriven and expanded upon this way and provides some more flexibility (obviously a little off scope of primary issue though but fun to think about). |
Using the history package directly proved to be a good solution for my use case, which only requires to read/write from the url. |
The post @MeiKatz shared is great. I think a potential solution is to have the I think the simplest solution is to ship the current context as-is + a history context but maybe there's a compelling reason to break the current context apart more. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
Can we keep this issue open? |
Yeah this is kinda annoying. I've switched to using the history library so that my components don't re-render on every browser url change. |
Yeah, is there an update on this? Every time a low level component tries to 'useHistory' it causes the entire tree to rerender which is super slow. At present I'm at somewhat of a loss for what to do aside from either writing my own useHistory hook or switch to a redux based router that allows history changes by dispatching actions.... |
@m-sterspace Yep, there is a PR awaiting to be merged which fixes the issue by separating the history object to its own context. (see: #7103) I'm not sure of when we can expect it to be merged though. |
#7103 got merged, so i think we can close this issue now. Thank you @illuminist for the PR and all for your feedbacks :) |
I noticed an important slowdown of my application (running in development build but i think it's a good practice to optimize from it) when route change occurred. At first i thought it was some deep bug between the Redux dispatch lifecycle with
react-redux
clashing with the one ofreact-router
since i was dispatching an action at the same time as changing the route but recently i switched to using hooks from the newreact-router
API and inspected what they were actually doing, leading me to notice that it just usesuseContext
fromreact
API and extract the right property from it.https://github.com/ReactTraining/react-router/blob/ea44618e68f6a112e48404b2ea0da3e207daf4f0/packages/react-router/modules/hooks.js#L17
The problem is that whenever the
react-router
context value is updated on a route change, theuseHistory
hook causes a re-render of the component which is using it since the new context value is just a new object containing the newly computed values along with thehistory
prop.Since it should not be a problem in most applications, my use case was one where the re-render caused at every route changes were a major performance issue. I use
useHistory
(mostly for calling navigation methods) in a lot of components which stay mounted even when a route change since my application is mostly modal-based. This means that at every route change, there is every components usinguseHistory
which re-render, and even while usingmemo
in some of them the performance are not that great.Since the
history
prop is not likely to change (or even probably never changes since it's a mutable object, but still not a hundred percent sure) i decided to implement a custom context which will act as a "tank-and-proxy" of thereact-router
context for thehistory
props:and i define my own
useHistory
hooks like so:And as a test component:
By using my custom
useHistory
, performances were back to normal on route changes.I'm wondering if this would be possible to implement this behavior of "standalone" history context in the current codebase. It's probably not possible from the
withRouter
HOC since it involves a lot of things outside of thehistory
props (and moving the history prop to awithHistory
HOC would break every apps usingwithRouter
to access the history), but it would be probably a lot easier to do it from theuseHistory
hook.Also i assume that my custom implementation is safe from a lifecycle point of view but it can be a wrong assumption since i'm not that familiar with the
react-router
codebase, so correct me if i'm wrong.Keep up the good work 👍
The text was updated successfully, but these errors were encountered: