Files
flipper/desktop/plugins/public/reactdevtools/DevToolsEmbedder.tsx
Michel Weststrate 96cbc81e63 Fix connection and DOM management of React DevTools
Summary:
This diff fixes several existing issues in the React DevTools:

Every time the user opened the plugin we re-instantiated the devtools, which has a few problems: 1) it looses all state (e.g. selection), and 2) this causes the tools to start a websocket listener on a new port, that was never cleaned up, or ever used, since React Native always connects to port 8097 anyway.

To preserve the state the idea of the original implementation was to move the devTools out of the current view, without disposing it. This actually didn't work in practice due to a faulty implementation, causing a full reinialization of the tools every time. Addressed this by reusing the mechanism that is used by the Hermes debugger tools as well.

By properly managing the port (e.g. closing it), there is no need to start (in vain) the devTools on a random port.

Port reversal for physical devices needs to happen only once, in principle upon connecting the device, so moved it to the device logic, which also avoids the need to hack into the global Flipper store.

Avoiding recreating the devTools makes plugin switching near instant, instead of needing to wait for a few seconds until the devTools connect.

When multiple apps are connected the behavior is now consistent: the application that refreshed last will be the one visible in the devTools. (That is still pretty suboptimal, but at least predicable and not a use case that is requested / supported in the DevTools themselves atm)

There is still ugly DOM business going on, did put that in a stand alone component for now.
Didn't extract the shared logic with Hermes plugin yet, but did verify both are still working correctly.

Changelog: [React DevTools] Several improvements that should improve the overal experience, the plugin should load much quicker and behave more predictably.

Reviewed By: bvaughn

Differential Revision: D28382587

fbshipit-source-id: 0f2787b24fa2afdf5014dbf1d79240606405199a
2021-05-12 14:21:53 -07:00

69 lines
1.8 KiB
TypeScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import {useEffect} from 'react';
// TODO: build abstraction of this: T62306732
const TARGET_CONTAINER_ID = 'flipper-out-of-contents-container'; // should be a hook in the future
export function DevToolsEmbedder({
offset,
nodeId,
}: {
offset: number;
nodeId: string;
}) {
useEffect(() => {
attachDevTools(createDevToolsNode(nodeId), offset);
return () => {
detachDevTools(findDevToolsNode(nodeId));
};
}, [offset, nodeId]);
return null;
}
function createDevToolsNode(nodeId: string): HTMLElement {
const existing = findDevToolsNode(nodeId);
if (existing) {
return existing;
}
const wrapper = document.createElement('div');
wrapper.id = nodeId;
wrapper.style.height = '100%';
wrapper.style.width = '100%';
document.getElementById(TARGET_CONTAINER_ID)!.appendChild(wrapper);
return wrapper;
}
function findDevToolsNode(nodeId: string): HTMLElement | null {
return document.querySelector('#' + nodeId);
}
function attachDevTools(devToolsNode: HTMLElement, offset: number = 0) {
devToolsNode.style.display = 'block';
const container = document.getElementById(TARGET_CONTAINER_ID)!;
container.style.display = 'block';
container.parentElement!.style.display = 'block';
container.parentElement!.style.height = `calc(100% - ${offset}px)`;
container.parentElement!.style.marginTop = '0px';
}
function detachDevTools(devToolsNode: HTMLElement | null) {
document.getElementById(TARGET_CONTAINER_ID)!.style.display = 'none';
document.getElementById(TARGET_CONTAINER_ID)!.parentElement!.style.display =
'none';
if (devToolsNode) {
devToolsNode.style.display = 'none';
}
}