Skip to content

Commit

Permalink
refactor[react-devtools/extensions]: dont debounce cleanup logic on n…
Browse files Browse the repository at this point in the history
…avigation (#30027)

## Summary
There is a race condition in the way we poll if React is on the page and
when we actually clear this polling instance. When user navigates to a
different page, we will debounce a callback for 500ms, which will:
1. Cleanup previous React polling instance
2. Start a new React polling instance

Since the cleanup logic is debounced, there is a small chance that by
the time we are going to clean up this polling instance, it will be
`eval`-ed on the page, that is using React. For example, when user is
navigating from the page which doesn't have React running, to a page
that has React running.

Next, we incorrectly will try to mount React DevTools panels twice,
which will result into conflicts in the Store, and the error will be
shown to the user

## How did you test this change?
Since this is a race condition, it is hard to reproduce consistently,
but you can try this flow:
1. Open a page that is using React, open browser DevTools and React
DevTools components panel
2. Open a page that is NOT using React, like google.com, wait ~5 seconds
until you see `"Looks like this page doesn't have React, or it hasn't
been loaded yet"` message in RDT panel
3. Open a page that is using React, observe the error `"Uncaught Error:
Cannot add node "1" because a node with that id is already in the
Store."`

Couldn't been able to reproduce this with these changes.
  • Loading branch information
hoxyq authored Jun 24, 2024
1 parent 27e9476 commit 7608516
Showing 1 changed file with 10 additions and 4 deletions.
14 changes: 10 additions & 4 deletions packages/react-devtools-extensions/src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -412,13 +412,19 @@ chrome.devtools.network.onNavigated.addListener(syncSavedPreferences);
// into subscribing to the same events from Bridge and window multiple times
// In this case, we will handle `operations` event twice or more and user will see
// `Cannot add node "1" because a node with that id is already in the Store.`
const debouncedOnNavigatedListener = debounce(() => {
const debouncedMountReactDevToolsCallback = debounce(
mountReactDevToolsWhenReactHasLoaded,
500,
);

// Clean up everything, but start mounting React DevTools panels if user stays at this page
function onNavigatedToOtherPage() {
performInTabNavigationCleanup();
mountReactDevToolsWhenReactHasLoaded();
}, 500);
debouncedMountReactDevToolsCallback();
}

// Cleanup previous page state and remount everything
chrome.devtools.network.onNavigated.addListener(debouncedOnNavigatedListener);
chrome.devtools.network.onNavigated.addListener(onNavigatedToOtherPage);

// Should be emitted when browser DevTools are closed
if (__IS_FIREFOX__) {
Expand Down

0 comments on commit 7608516

Please sign in to comment.