[DevTools] Apply component filters on initial load (#35587)
Sebastian "Sebbie" Silbermann committed
Jan 26, 2026 at 11:06 UTC
3e319a943cff862b8fbb8e96868f9f153a9e199d
15 files changed
+127
-106
packages/react-devtools-core/README.md
+18
-3
@@ -25,15 +25,30 @@ if (process.env.NODE_ENV !== 'production') {
25
> **NOTE** that this API (`connectToDevTools`) must be (1) run in the same context as React and (2) must be called before React packages are imported (e.g. `react`, `react-dom`, `react-native`).
26
27
### `initialize` arguments
28
-| Argument | Description |
29
-|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
30
-| `settings` | Optional. If not specified, or received as null, then default settings are used. Can be plain object or a Promise that resolves with the [plain settings object](#Settings). If Promise rejects, the console will not be patched and some console features from React DevTools will not work. |
28
+| Argument | Description |
29
+|---------------------------|-------------|
30
+| `settings` | Optional. If not specified, or received as null, then default settings are used. Can be plain object or a Promise that resolves with the [plain settings object](#Settings). If Promise rejects, the console will not be patched and some console features from React DevTools will not work. |
31
+| `shouldStartProfilingNow` | Optional. Whether to start profiling immediately after installing the hook. Defaults to `false`. |
32
+| `profilingSettings` | Optional. Profiling settings used when `shouldStartProfilingNow` is `true`. Defaults to `{ recordChangeDescriptions: false, recordTimeline: false }`. |
33
+| `componentFilters` | Optional. Array or Promise that resolves to an array of component filters to apply before DevTools connects. Defaults to the built-in host component filter. See [Component filters](#component-filters) for the full spec. |
34
35
#### `Settings`
36
| Spec | Default value |
37
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
38
| <pre>{<br> appendComponentStack: boolean,<br> breakOnConsoleErrors: boolean,<br> showInlineWarningsAndErrors: boolean,<br> hideConsoleLogsInStrictMode: boolean,<br> disableSecondConsoleLogDimmingInStrictMode: boolean<br>}</pre> | <pre>{<br> appendComponentStack: true,<br> breakOnConsoleErrors: false,<br> showInlineWarningsAndErrors: true,<br> hideConsoleLogsInStrictMode: false,<br> disableSecondConsoleLogDimmingInStrictMode: false<br>}</pre> |
39
40
+#### Component filters
41
+Each filter object must include `type` and `isEnabled`. Some filters also require `value` or `isValid`.
42
+
43
+| Type | Required fields | Description |
44
+|------|-----------------|-------------|
45
+| `ComponentFilterElementType` (`1`) | `type`, `isEnabled`, `value: ElementType` | Hides elements of the given element type. DevTools defaults to hiding host components. |
46
+| `ComponentFilterDisplayName` (`2`) | `type`, `isEnabled`, `isValid`, `value: string` | Hides components whose display name matches the provided RegExp string. |
47
+| `ComponentFilterLocation` (`3`) | `type`, `isEnabled`, `isValid`, `value: string` | Hides components whose source location matches the provided RegExp string. |
48
+| `ComponentFilterHOC` (`4`) | `type`, `isEnabled`, `isValid` | Hides higher-order components. |
49
+| `ComponentFilterEnvironmentName` (`5`) | `type`, `isEnabled`, `isValid`, `value: string` | Hides components whose environment name matches the provided string. |
50
+| `ComponentFilterActivitySlice` (`6`) | `type`, `isEnabled`, `isValid`, `activityID`, `rendererID` | Filters activity slices; usually managed by DevTools rather than user code. |
51
+
52
### `connectToDevTools` options
53
| Prop | Default | Description |
54
|------------------------|---------------|---------------------------------------------------------------------------------------------------------------------------|
packages/react-devtools-core/src/backend.js
+8
-17
@@ -66,9 +66,17 @@ export function initialize(
66
| Promise<DevToolsHookSettings>,
67
shouldStartProfilingNow: boolean = false,
68
profilingSettings?: ProfilingSettings,
69
+ maybeComponentFiltersOrComponentFiltersPromise?:
70
+ | Array<ComponentFilter>
71
+ | Promise<Array<ComponentFilter>>,
72
) {
73
+ const componentFiltersOrComponentFiltersPromise =
74
+ maybeComponentFiltersOrComponentFiltersPromise
75
+ ? maybeComponentFiltersOrComponentFiltersPromise
76
+ : savedComponentFilters;
77
installHook(
78
window,
79
+ componentFiltersOrComponentFiltersPromise,
80
maybeSettingsOrSettingsPromise,
81
shouldStartProfilingNow,
82
profilingSettings,
@@ -174,19 +182,6 @@ export function connectToDevTools(options: ?ConnectOptions) {
182
},
183
);
184
177
- // The renderer interface doesn't read saved component filters directly,
178
- // because they are generally stored in localStorage within the context of the extension.
179
- // Because of this it relies on the extension to pass filters.
180
- // In the case of the standalone DevTools being used with a website,
181
- // saved filters are injected along with the backend script tag so we shouldn't override them here.
182
- // This injection strategy doesn't work for React Native though.
183
- // Ideally the backend would save the filters itself, but RN doesn't provide a sync storage solution.
184
- // So for now we just fall back to using the default filters...
185
- if (window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ == null) {
186
- // $FlowFixMe[incompatible-use] found when upgrading Flow
187
- bridge.send('overrideComponentFilters', savedComponentFilters);
188
- }
189
-
185
// TODO (npm-packages) Warn if "isBackendStorageAPISupported"
186
// $FlowFixMe[incompatible-call] found when upgrading Flow
187
const agent = new Agent(bridge, isProfiling, onReloadAndProfile);
@@ -381,10 +376,6 @@ export function connectWithCustomMessagingProtocol({
376
},
377
);
378
384
- if (window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ == null) {
385
- bridge.send('overrideComponentFilters', savedComponentFilters);
386
- }
387
-
379
const agent = new Agent(bridge, isProfiling, onReloadAndProfile);
380
if (typeof onReloadAndProfileFlagsReset === 'function') {
381
onReloadAndProfileFlagsReset();
packages/react-devtools-core/src/standalone.js
+3
-8
@@ -356,17 +356,12 @@ function startServer(
356
// because they are generally stored in localStorage within the context of the extension.
357
// Because of this it relies on the extension to pass filters, so include them wth the response here.
358
// This will ensure that saved filters are shared across different web pages.
359
- const savedPreferencesString = `
360
- window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = ${JSON.stringify(
361
- getSavedComponentFilters(),
362
- )};`;
359
+ const componentFiltersString = JSON.stringify(getSavedComponentFilters());
360
361
response.end(
365
- savedPreferencesString +
362
+ backendFile.toString() +
363
'\n;' +
367
- backendFile.toString() +
368
- '\n;' +
369
- 'ReactDevToolsBackend.initialize();' +
364
+ `ReactDevToolsBackend.initialize(undefined, undefined, undefined, ${componentFiltersString});` +
365
'\n' +
366
`ReactDevToolsBackend.connectToDevTools({port: ${port}, host: '${host}', useHttps: ${
367
useHttps ? 'true' : 'false'
packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js
+16
-5
@@ -5,9 +5,15 @@
5
// This is the only purpose of this script - to send persisted settings to installHook.js content script
6
7
import type {UnknownMessageEvent} from './messages';
8
-import type {DevToolsHookSettings} from 'react-devtools-shared/src/backend/types';
8
+import type {
9
+ DevToolsHookSettings,
10
+ DevToolsSettings,
11
+} from 'react-devtools-shared/src/backend/types';
12
+import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types';
13
import {postMessage} from './messages';
14
15
+import {getDefaultComponentFilters} from 'react-devtools-shared/src/utils';
16
+
17
async function messageListener(event: UnknownMessageEvent) {
18
if (event.source !== window) {
19
return;
@@ -15,7 +21,7 @@ async function messageListener(event: UnknownMessageEvent) {
21
22
if (event.data.source === 'react-devtools-hook-installer') {
23
if (event.data.payload.handshake) {
18
- const settings: Partial<DevToolsHookSettings> =
24
+ const settings: Partial<DevToolsSettings> =
25
await chrome.storage.local.get();
26
// If storage was empty (first installation), define default settings
27
const hookSettings: DevToolsHookSettings = {
@@ -41,10 +47,15 @@ async function messageListener(event: UnknownMessageEvent) {
47
? settings.disableSecondConsoleLogDimmingInStrictMode
48
: false,
49
};
50
+ const componentFilters: Array<ComponentFilter> = Array.isArray(
51
+ settings.componentFilters,
52
+ )
53
+ ? settings.componentFilters
54
+ : getDefaultComponentFilters();
55
56
postMessage({
46
- source: 'react-devtools-hook-settings-injector',
47
- payload: {settings: hookSettings},
57
+ source: 'react-devtools-settings-injector',
58
+ payload: {hookSettings, componentFilters},
59
});
60
61
window.removeEventListener('message', messageListener);
@@ -54,6 +65,6 @@ async function messageListener(event: UnknownMessageEvent) {
65
66
window.addEventListener('message', messageListener);
67
postMessage({
57
- source: 'react-devtools-hook-settings-injector',
68
+ source: 'react-devtools-settings-injector',
69
payload: {handshake: true},
70
});
packages/react-devtools-extensions/src/contentScripts/installHook.js
+12
-3
@@ -2,6 +2,7 @@
2
3
import type {UnknownMessageEvent} from './messages';
4
import type {DevToolsHookSettings} from 'react-devtools-shared/src/backend/types';
5
+import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types';
6
7
import {installHook} from 'react-devtools-shared/src/hook';
8
import {
@@ -11,13 +12,14 @@ import {
12
import {postMessage} from './messages';
13
14
let resolveHookSettingsInjection: (settings: DevToolsHookSettings) => void;
15
+let resolveComponentFiltersInjection: (filters: Array<ComponentFilter>) => void;
16
17
function messageListener(event: UnknownMessageEvent) {
18
if (event.source !== window) {
19
return;
20
}
21
20
- if (event.data.source === 'react-devtools-hook-settings-injector') {
22
+ if (event.data.source === 'react-devtools-settings-injector') {
23
const payload = event.data.payload;
24
// In case handshake message was sent prior to hookSettingsInjector execution
25
// We can't guarantee order
@@ -26,9 +28,10 @@ function messageListener(event: UnknownMessageEvent) {
28
source: 'react-devtools-hook-installer',
29
payload: {handshake: true},
30
});
29
- } else if (payload.settings) {
31
+ } else if (payload.hookSettings) {
32
window.removeEventListener('message', messageListener);
31
- resolveHookSettingsInjection(payload.settings);
33
+ resolveHookSettingsInjection(payload.hookSettings);
34
+ resolveComponentFiltersInjection(payload.componentFilters);
35
}
36
}
37
}
@@ -38,6 +41,11 @@ if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) {
41
const hookSettingsPromise = new Promise<DevToolsHookSettings>(resolve => {
42
resolveHookSettingsInjection = resolve;
43
});
44
+ const componentFiltersPromise = new Promise<Array<ComponentFilter>>(
45
+ resolve => {
46
+ resolveComponentFiltersInjection = resolve;
47
+ },
48
+ );
49
50
window.addEventListener('message', messageListener);
51
postMessage({
@@ -50,6 +58,7 @@ if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) {
58
// Can't delay hook installation, inject settings lazily
59
installHook(
60
window,
61
+ componentFiltersPromise,
62
hookSettingsPromise,
63
shouldStartProfiling,
64
profilingSettings,
packages/react-devtools-extensions/src/contentScripts/messages.js
+12
-10
@@ -1,6 +1,7 @@
1
/** @flow */
2
3
import type {DevToolsHookSettings} from 'react-devtools-shared/src/backend/types';
4
+import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types';
5
6
export function postMessage(event: UnknownMessageEventData): void {
7
window.postMessage(event);
@@ -10,7 +11,7 @@ export interface UnknownMessageEvent
11
extends MessageEvent<UnknownMessageEventData> {}
12
13
export type UnknownMessageEventData =
13
- | HookSettingsInjectorEventData
14
+ | SettingsInjectorEventData
15
| HookInstallerEventData;
16
17
export type HookInstallerEventData = {
@@ -24,19 +25,20 @@ export type HookInstallerEventPayloadHandshake = {
25
handshake: true,
26
};
27
27
-export type HookSettingsInjectorEventData = {
28
- source: 'react-devtools-hook-settings-injector',
29
- payload: HookSettingsInjectorEventPayload,
28
+export type SettingsInjectorEventData = {
29
+ source: 'react-devtools-settings-injector',
30
+ payload: SettingsInjectorEventPayload,
31
};
32
32
-export type HookSettingsInjectorEventPayload =
33
- | HookSettingsInjectorEventPayloadHandshake
34
- | HookSettingsInjectorEventPayloadSettings;
33
+export type SettingsInjectorEventPayload =
34
+ | SettingsInjectorEventPayloadHandshake
35
+ | SettingsInjectorEventPayloadSettings;
36
36
-export type HookSettingsInjectorEventPayloadHandshake = {
37
+export type SettingsInjectorEventPayloadHandshake = {
38
handshake: true,
39
};
40
40
-export type HookSettingsInjectorEventPayloadSettings = {
41
- settings: DevToolsHookSettings,
41
+export type SettingsInjectorEventPayloadSettings = {
42
+ hookSettings: DevToolsHookSettings,
43
+ componentFilters: Array<ComponentFilter>,
44
};
packages/react-devtools-extensions/src/main/index.js
+2
-2
@@ -171,8 +171,8 @@ function createBridgeAndStore() {
171
createSuspensePanel();
172
});
173
174
- store.addListener('settingsUpdated', settings => {
175
- chrome.storage.local.set(settings);
174
+ store.addListener('settingsUpdated', (hookSettings, componentFilters) => {
175
+ chrome.storage.local.set({...hookSettings, componentFilters});
176
});
177
178
if (!isProfiling) {
packages/react-devtools-inline/src/backend.js
+15
-15
@@ -10,7 +10,10 @@ import type {
10
BackendBridge,
11
SavedPreferencesParams,
12
} from 'react-devtools-shared/src/bridge';
13
-import type {Wall} from 'react-devtools-shared/src/frontend/types';
13
+import type {
14
+ ComponentFilter,
15
+ Wall,
16
+} from 'react-devtools-shared/src/frontend/types';
17
import {
18
getIfReloadedAndProfiling,
19
getIsReloadAndProfileSupported,
@@ -18,6 +21,11 @@ import {
21
onReloadAndProfileFlagsReset,
22
} from 'react-devtools-shared/src/utils';
23
24
+let resolveComponentFiltersInjection: (filters: Array<ComponentFilter>) => void;
25
+const componentFiltersPromise = new Promise<Array<ComponentFilter>>(resolve => {
26
+ resolveComponentFiltersInjection = resolve;
27
+});
28
+
29
function startActivation(contentWindow: any, bridge: BackendBridge) {
30
const onSavedPreferences = (data: SavedPreferencesParams) => {
31
// This is the only message we're listening for,
@@ -26,21 +34,13 @@ function startActivation(contentWindow: any, bridge: BackendBridge) {
34
35
const {componentFilters} = data;
36
29
- contentWindow.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters;
30
-
31
- // TRICKY
32
- // The backend entry point may be required in the context of an iframe or the parent window.
33
- // If it's required within the parent window, store the saved values on it as well,
34
- // since the injected renderer interface will read from window.
35
- // Technically we don't need to store them on the contentWindow in this case,
36
- // but it doesn't really hurt anything to store them there too.
37
- if (contentWindow !== window) {
38
- window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters;
39
- }
40
-
41
- finishActivation(contentWindow, bridge);
37
+ resolveComponentFiltersInjection(componentFilters);
38
};
39
40
+ componentFiltersPromise.then(
41
+ finishActivation.bind(null, contentWindow, bridge),
42
+ );
43
+
44
bridge.addListener('savedPreferences', onSavedPreferences);
45
46
// The backend may be unable to read saved preferences directly,
@@ -113,5 +113,5 @@ export function createBridge(contentWindow: any, wall?: Wall): BackendBridge {
113
}
114
115
export function initialize(contentWindow: any): void {
116
- installHook(contentWindow);
116
+ installHook(contentWindow, componentFiltersPromise);
117
}
packages/react-devtools-shared/src/__tests__/setupTests.js
+1
-2
@@ -238,9 +238,8 @@ beforeEach(() => {
238
239
// Initialize filters to a known good state.
240
setSavedComponentFilters(getDefaultComponentFilters());
241
- global.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = getDefaultComponentFilters();
241
243
- installHook(global, {
242
+ installHook(global, getDefaultComponentFilters(), {
243
appendComponentStack: true,
244
breakOnConsoleErrors: false,
245
showInlineWarningsAndErrors: true,
packages/react-devtools-shared/src/attachRenderer.js
+5
@@ -14,6 +14,7 @@ import type {
14
RendererID,
15
ProfilingSettings,
16
} from 'react-devtools-shared/src/backend/types';
17
+import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types';
18
19
import {attach as attachFlight} from 'react-devtools-shared/src/backend/flight/renderer';
20
import {attach as attachFiber} from 'react-devtools-shared/src/backend/fiber/renderer';
@@ -32,6 +33,9 @@ export default function attachRenderer(
33
global: Object,
34
shouldStartProfilingNow: boolean,
35
profilingSettings: ProfilingSettings,
36
+ componentFiltersOrComponentFiltersPromise:
37
+ | Array<ComponentFilter>
38
+ | Promise<Array<ComponentFilter>>,
39
): RendererInterface | void {
40
// only attach if the renderer is compatible with the current version of the backend
41
if (!isMatchingRender(renderer.reconcilerVersion || renderer.version)) {
@@ -58,6 +62,7 @@ export default function attachRenderer(
62
global,
63
shouldStartProfilingNow,
64
profilingSettings,
65
+ componentFiltersOrComponentFiltersPromise,
66
);
67
} else if (renderer.ComponentTree) {
68
// react-dom v15
packages/react-devtools-shared/src/backend/fiber/renderer.js
+8
-16
@@ -48,13 +48,11 @@ import {
48
deletePathInObject,
49
getDisplayName,
50
getWrappedDisplayName,
51
- getDefaultComponentFilters,
51
getInObject,
52
getUID,
53
renamePathInObject,
54
setInObject,
55
utfEncodeString,
57
- persistableComponentFilters,
56
} from 'react-devtools-shared/src/utils';
57
import {
58
formatConsoleArgumentsToSingleString,
@@ -1010,6 +1008,9 @@ export function attach(
1008
global: Object,
1009
shouldStartProfilingNow: boolean,
1010
profilingSettings: ProfilingSettings,
1011
+ componentFiltersOrComponentFiltersPromise:
1012
+ | Array<ComponentFilter>
1013
+ | Promise<Array<ComponentFilter>>,
1014
): RendererInterface {
1015
// Newer versions of the reconciler package also specific reconciler version.
1016
// If that version number is present, use it.
@@ -1516,21 +1517,12 @@ export function attach(
1517
});
1518
}
1519
1519
- // The renderer interface can't read saved component filters directly,
1520
- // because they are stored in localStorage within the context of the extension.
1521
- // Instead it relies on the extension to pass filters through.
1522
- if (window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ != null) {
1523
- const restoredComponentFilters: Array<ComponentFilter> =
1524
- persistableComponentFilters(window.__REACT_DEVTOOLS_COMPONENT_FILTERS__);
1525
- applyComponentFilters(restoredComponentFilters, null);
1520
+ if (Array.isArray(componentFiltersOrComponentFiltersPromise)) {
1521
+ applyComponentFilters(componentFiltersOrComponentFiltersPromise, null);
1522
} else {
1527
- // Unfortunately this feature is not expected to work for React Native for now.
1528
- // It would be annoying for us to spam YellowBox warnings with unactionable stuff,
1529
- // so for now just skip this message...
1530
- //console.warn('⚛ DevTools: Could not locate saved component filters');
1531
-
1532
- // Fallback to assuming the default filters in this case.
1533
- applyComponentFilters(getDefaultComponentFilters(), null);
1523
+ componentFiltersOrComponentFiltersPromise.then(componentFilters => {
1524
+ applyComponentFilters(componentFilters, null);
1525
+ });
1526
}
1527
1528
// If necessary, we can revisit optimizing this operation.
packages/react-devtools-shared/src/backend/types.js
+4
@@ -599,3 +599,7 @@ export type DevToolsHookSettings = {
599
hideConsoleLogsInStrictMode: boolean,
600
disableSecondConsoleLogDimmingInStrictMode: boolean,
601
};
602
+
603
+export type DevToolsSettings = DevToolsHookSettings & {
604
+ componentFilters: Array<ComponentFilter>,
605
+};
packages/react-devtools-shared/src/bridge.js
-1
@@ -208,7 +208,6 @@ export type BackendEvents = {
208
isReloadAndProfileSupportedByBackend: [boolean],
209
operations: [Array<number>],
210
ownersList: [OwnersList],
211
- overrideComponentFilters: [Array<ComponentFilter>],
211
environmentNames: [Array<string>],
212
profilingData: [ProfilingDataBackend],
213
profilingStatus: [boolean],
packages/react-devtools-shared/src/devtools/store.js
+18
-24
@@ -148,7 +148,7 @@ export default class Store extends EventEmitter<{
148
error: [Error],
149
hookSettings: [$ReadOnly<DevToolsHookSettings>],
150
hostInstanceSelected: [Element['id'] | null],
151
- settingsUpdated: [$ReadOnly<DevToolsHookSettings>],
151
+ settingsUpdated: [$ReadOnly<DevToolsHookSettings>, Array<ComponentFilter>],
152
mutated: [
153
[
154
Array<Element['id']>,
@@ -321,10 +321,6 @@ export default class Store extends EventEmitter<{
321
322
this._bridge = bridge;
323
bridge.addListener('operations', this.onBridgeOperations);
324
- bridge.addListener(
325
- 'overrideComponentFilters',
326
- this.onBridgeOverrideComponentFilters,
327
- );
324
bridge.addListener('shutdown', this.onBridgeShutdown);
325
bridge.addListener(
326
'isReloadAndProfileSupportedByBackend',
@@ -437,8 +433,23 @@ export default class Store extends EventEmitter<{
433
434
this._componentFilters = value;
435
440
- // Update persisted filter preferences stored in localStorage.
436
+ // Update persisted filter preferences
437
setSavedComponentFilters(value);
438
+ if (this._hookSettings === null) {
439
+ // We changed filters before we got the hook settings.
440
+ // Wait for hook settings before persisting component filters to not overwrite
441
+ // persisted hook settings with defaults.
442
+ // This exists purely as a type safety check; in practice the hook settings
443
+ // should have arrived before any filter changes could be made.
444
+ const onHookSettings = (settings: $ReadOnly<DevToolsHookSettings>) => {
445
+ this._bridge.removeListener('hookSettings', onHookSettings);
446
+ this.emit('settingsUpdated', settings, value);
447
+ };
448
+ this._bridge.addListener('hookSettings', onHookSettings);
449
+ this._bridge.send('getHookSettings');
450
+ } else {
451
+ this.emit('settingsUpdated', this._hookSettings, value);
452
+ }
453
454
// Notify the renderer that filter preferences have changed.
455
// This is an expensive operation; it unmounts and remounts the entire tree,
@@ -2264,19 +2275,6 @@ export default class Store extends EventEmitter<{
2275
return didMutate;
2276
}
2277
2267
- // Certain backends save filters on a per-domain basis.
2268
- // In order to prevent filter preferences and applied filters from being out of sync,
2269
- // this message enables the backend to override the frontend's current ("saved") filters.
2270
- // This action should also override the saved filters too,
2271
- // else reloading the frontend without reloading the backend would leave things out of sync.
2272
- onBridgeOverrideComponentFilters: (
2273
- componentFilters: Array<ComponentFilter>,
2274
- ) => void = componentFilters => {
2275
- this._componentFilters = componentFilters;
2276
-
2277
- setSavedComponentFilters(componentFilters);
2278
- };
2279
-
2278
onBridgeShutdown: () => void = () => {
2279
if (__DEBUG__) {
2280
debug('onBridgeShutdown', 'unsubscribing from Bridge');
@@ -2284,10 +2282,6 @@ export default class Store extends EventEmitter<{
2282
2283
const bridge = this._bridge;
2284
bridge.removeListener('operations', this.onBridgeOperations);
2287
- bridge.removeListener(
2288
- 'overrideComponentFilters',
2289
- this.onBridgeOverrideComponentFilters,
2290
- );
2285
bridge.removeListener('shutdown', this.onBridgeShutdown);
2286
bridge.removeListener(
2287
'isReloadAndProfileSupportedByBackend',
@@ -2419,7 +2413,7 @@ export default class Store extends EventEmitter<{
2413
this._hookSettings = settings;
2414
2415
this._bridge.send('updateHookSettings', settings);
2422
- this.emit('settingsUpdated', settings);
2416
+ this.emit('settingsUpdated', settings, this._componentFilters);
2417
};
2418
2419
onHookSettings: (settings: $ReadOnly<DevToolsHookSettings>) => void =
packages/react-devtools-shared/src/hook.js
+5
@@ -18,6 +18,7 @@ import type {
18
DevToolsHookSettings,
19
ProfilingSettings,
20
} from './backend/types';
21
+import type {ComponentFilter} from './frontend/types';
22
23
import {
24
FIREFOX_CONSOLE_DIMMING_COLOR,
@@ -57,6 +58,9 @@ const defaultProfilingSettings: ProfilingSettings = {
58
59
export function installHook(
60
target: any,
61
+ componentFiltersOrComponentFiltersPromise:
62
+ | Array<ComponentFilter>
63
+ | Promise<Array<ComponentFilter>>,
64
maybeSettingsOrSettingsPromise?:
65
| DevToolsHookSettings
66
| Promise<DevToolsHookSettings>,
@@ -224,6 +228,7 @@ export function installHook(
228
target,
229
isProfiling,
230
profilingSettings,
231
+ componentFiltersOrComponentFiltersPromise,
232
);
233
if (rendererInterface != null) {
234
hook.rendererInterfaces.set(id, rendererInterface);