Skip to content
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

[Bug]: "react-router-dom-v5-compat" <CompatRouter> doesn't unsubscribe from history potentially causing tests to memory leak #11799

Closed
chi11ed opened this issue Jul 12, 2024 · 2 comments
Labels

Comments

@chi11ed
Copy link

chi11ed commented Jul 12, 2024

What version of React Router are you using?

Latest "react-router-dom-v5-compat"

Steps to Reproduce

  1. Have a global instance of history created and shared
  2. Run jest tests
  3. Before rendering a test case by React use directly historyInstance.replace() (or any other manipulation) to set up history URL or have legacy tests which can do something with history not awaiting all the promises.

Expected Behavior

<CompatRouter> should stop listening history on unmount

Actual Behavior

Here unsubscribe function is not returned from the effect.

Depending on a mess in tests, it is

  • Either this error output
    Warning: An update to CompatRouter inside a test was not wrapped in act(...).
    
    When testing, code that causes React state updates should be wrapped into act(...):
    
    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */
  • Or this error output
  console.error
    Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
@chi11ed chi11ed added the bug label Jul 12, 2024
@timdorr
Copy link
Member

timdorr commented Jul 12, 2024

This is a side-effect of the transition to v6. You no longer have history instances in that version, so there is no need to unsubscribe. The state data disappears when the component is unmounted. For the transition to v6, CompatRouter is not intended to be used long-term and may have quirks while you use it. It is only for a faster transition to v6 and should be removed as soon as you no longer have v5 code in place.

@timdorr timdorr closed this as completed Jul 12, 2024
@chi11ed
Copy link
Author

chi11ed commented Jul 13, 2024

@timdorr Thanks for taking a look 👍 I understand CompatRouter is not intended to be used long-term, but for large projects which have some legacy unpleasant moments it yet might take a bit longer, and what is needed to make transition more stable is just to properly clean up things and unsubscribe from things it was subscribed.

By unpleasant moments in legacy projects I mean simply this:

// historyInstance.ts
export const history = createBrowserHistory({ basename: '/something' })

// router.tsx
import { Router } from 'react-router-dom'
import { CompatRouter } from 'react-router-dom-v5-compat'

function RouterProvider({ history, routes }: RouterProviderProps) {
  return (
    <Router history={history}>
      <CompatRouter>

Regardless of amount of time which ComparRouter is being used and migration to v6 is happening - currently it has an impact on tests, because N tests within 1 spec mount N CompatRouters and neither of those unsubscribing it causing memory leaks.

The state data disappears when the component is unmounted.

As explained above, it's not a problem of resetting state - it's a problem of memory leaks in projects which unfortunately can't quickly get rid of shared history instance.
Would that be possible to reopen he issue and yet fix missing cleanup? In the end I assume we all agree that cleanups in software are important to avoid undesired things :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants