mirror of
https://github.com/facebook/react.git
synced 2026-02-26 03:54:58 +00:00
## Summary We have a case: 1. Open components tab 2. Close Chrome / Firefox devtools window completely 3. Reopen browser devtools panel 4. Open components tab Currently, in version 4.27.6, we cannot load the components tree. This PR contains two changes: - non-functional refactoring in `react-devtools-shared/src/devtools/store.js`: removed some redundant type castings. - fixed backend manager logic (introduced in https://github.com/facebook/react/pull/26615) to activate already registered backends. Looks like frontend of devtools also depends on `renderer-attached` event, without it component tree won't load. ## How did you test this change? This fixes the case mentioned prior. Currently in 4.27.6 version it is not working, we need to refresh the page to make it work. I've tested this in several environments: chrome, firefox, standalone with RN application.
137 lines
3.8 KiB
JavaScript
137 lines
3.8 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import Agent from './agent';
|
|
|
|
import {attach} from './renderer';
|
|
import {attach as attachLegacy} from './legacy/renderer';
|
|
import {hasAssignedBackend} from './utils';
|
|
|
|
import type {DevToolsHook, ReactRenderer, RendererInterface} from './types';
|
|
|
|
// this is the backend that is compatible with all older React versions
|
|
function isMatchingRender(version: string): boolean {
|
|
return !hasAssignedBackend(version);
|
|
}
|
|
|
|
export type InitBackend = typeof initBackend;
|
|
|
|
export function initBackend(
|
|
hook: DevToolsHook,
|
|
agent: Agent,
|
|
global: Object,
|
|
): () => void {
|
|
if (hook == null) {
|
|
// DevTools didn't get injected into this page (maybe b'c of the contentType).
|
|
return () => {};
|
|
}
|
|
|
|
const subs = [
|
|
hook.sub(
|
|
'renderer-attached',
|
|
({
|
|
id,
|
|
renderer,
|
|
rendererInterface,
|
|
}: {
|
|
id: number,
|
|
renderer: ReactRenderer,
|
|
rendererInterface: RendererInterface,
|
|
...
|
|
}) => {
|
|
agent.setRendererInterface(id, rendererInterface);
|
|
|
|
// Now that the Store and the renderer interface are connected,
|
|
// it's time to flush the pending operation codes to the frontend.
|
|
rendererInterface.flushInitialOperations();
|
|
},
|
|
),
|
|
|
|
hook.sub('unsupported-renderer-version', (id: number) => {
|
|
agent.onUnsupportedRenderer(id);
|
|
}),
|
|
|
|
hook.sub('fastRefreshScheduled', agent.onFastRefreshScheduled),
|
|
hook.sub('operations', agent.onHookOperations),
|
|
hook.sub('traceUpdates', agent.onTraceUpdates),
|
|
|
|
// TODO Add additional subscriptions required for profiling mode
|
|
];
|
|
|
|
const attachRenderer = (id: number, renderer: ReactRenderer) => {
|
|
// only attach if the renderer is compatible with the current version of the backend
|
|
if (!isMatchingRender(renderer.reconcilerVersion || renderer.version)) {
|
|
return;
|
|
}
|
|
let rendererInterface = hook.rendererInterfaces.get(id);
|
|
|
|
// Inject any not-yet-injected renderers (if we didn't reload-and-profile)
|
|
if (rendererInterface == null) {
|
|
if (typeof renderer.findFiberByHostInstance === 'function') {
|
|
// react-reconciler v16+
|
|
rendererInterface = attach(hook, id, renderer, global);
|
|
} else if (renderer.ComponentTree) {
|
|
// react-dom v15
|
|
rendererInterface = attachLegacy(hook, id, renderer, global);
|
|
} else {
|
|
// Older react-dom or other unsupported renderer version
|
|
}
|
|
|
|
if (rendererInterface != null) {
|
|
hook.rendererInterfaces.set(id, rendererInterface);
|
|
}
|
|
}
|
|
|
|
// Notify the DevTools frontend about new renderers.
|
|
// This includes any that were attached early (via __REACT_DEVTOOLS_ATTACH__).
|
|
if (rendererInterface != null) {
|
|
hook.emit('renderer-attached', {
|
|
id,
|
|
renderer,
|
|
rendererInterface,
|
|
});
|
|
} else {
|
|
hook.emit('unsupported-renderer-version', id);
|
|
}
|
|
};
|
|
|
|
// Connect renderers that have already injected themselves.
|
|
hook.renderers.forEach((renderer, id) => {
|
|
attachRenderer(id, renderer);
|
|
});
|
|
|
|
// Connect any new renderers that injected themselves.
|
|
subs.push(
|
|
hook.sub(
|
|
'renderer',
|
|
({id, renderer}: {id: number, renderer: ReactRenderer, ...}) => {
|
|
attachRenderer(id, renderer);
|
|
},
|
|
),
|
|
);
|
|
|
|
hook.emit('react-devtools', agent);
|
|
hook.reactDevtoolsAgent = agent;
|
|
const onAgentShutdown = () => {
|
|
subs.forEach(fn => fn());
|
|
hook.rendererInterfaces.forEach(rendererInterface => {
|
|
rendererInterface.cleanup();
|
|
});
|
|
hook.reactDevtoolsAgent = null;
|
|
};
|
|
agent.addListener('shutdown', onAgentShutdown);
|
|
subs.push(() => {
|
|
agent.removeListener('shutdown', onAgentShutdown);
|
|
});
|
|
|
|
return () => {
|
|
subs.forEach(fn => fn());
|
|
};
|
|
}
|