@samitouri / QOS-React-2 / commits / 3e319a943c

[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);