DevTools shows unsupported renderer version dialog (#16897)

* DevTools shows unsupported renderer version dialog

* Optimistic CHANGELOG udpate
This commit is contained in:
Brian Vaughn
2019-09-26 08:41:46 -07:00
committed by GitHub
parent 84e83db1ee
commit b6606ecba8
12 changed files with 161 additions and 10 deletions

View File

@@ -161,7 +161,7 @@ function createPanelIfReactLoaded() {
overrideTab,
profilerPortalContainer,
showTabBar: false,
showWelcomeToTheNewDevToolsDialog: true,
warnIfUnsupportedVersionDetected: true,
store,
viewElementSourceFunction,
}),

View File

@@ -474,6 +474,10 @@ export default class Agent extends EventEmitter<{|
}
};
onUnsupportedRenderer(rendererID: number) {
this._bridge.send('unsupportedRendererVersion', rendererID);
}
_throttledPersistSelection = throttle((rendererID: number, id: number) => {
// This is throttled, so both renderer and selected ID
// might not be available by the time we read them.

View File

@@ -39,6 +39,10 @@ export function initBackend(
},
),
hook.sub('unsupported-renderer-version', (id: number) => {
agent.onUnsupportedRenderer(id);
}),
hook.sub('operations', agent.onHookOperations),
// TODO Add additional subscriptions required for profiling mode
@@ -48,23 +52,33 @@ export function initBackend(
let rendererInterface = hook.rendererInterfaces.get(id);
// Inject any not-yet-injected renderers (if we didn't reload-and-profile)
if (!rendererInterface) {
if (rendererInterface == null) {
if (typeof renderer.findFiberByHostInstance === 'function') {
// react-reconciler v16+
rendererInterface = attach(hook, id, renderer, global);
} else {
} else if (renderer.ComponentTree) {
// react-dom v15
rendererInterface = attachLegacy(hook, id, renderer, global);
} else {
// Older react-dom or other unsupported renderer version
}
hook.rendererInterfaces.set(id, rendererInterface);
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__).
hook.emit('renderer-attached', {
id,
renderer,
rendererInterface,
});
if (rendererInterface != null) {
hook.emit('renderer-attached', {
id,
renderer,
rendererInterface,
});
} else {
hook.emit('unsupported-renderer-version', id);
}
};
// Connect renderers that have already injected themselves.

View File

@@ -81,7 +81,10 @@ export type ReactRenderer = {
// Enables DevTools to append owners-only component stack to error messages.
getCurrentFiber?: () => Fiber | null,
// <= 15
// Uniquely identifies React DOM v15.
ComponentTree?: any,
// Present for React DOM v12 (possibly earlier) through v15.
Mount?: any,
};

View File

@@ -83,6 +83,7 @@ type BackendEvents = {|
stopInspectingNative: [boolean],
syncSelectionFromNativeElementsPanel: [],
syncSelectionToNativeElementsPanel: [],
unsupportedRendererVersion: [RendererID],
// React Native style editor plug-in.
isNativeStyleEditorSupported: [

View File

@@ -35,6 +35,9 @@ export const PROFILER_EXPORT_VERSION = 4;
export const CHANGE_LOG_URL =
'https://github.com/facebook/react/blob/master/packages/react-devtools/CHANGELOG.md';
export const UNSUPPORTED_VERSION_URL =
'https://reactjs.org/blog/2019/08/15/new-react-devtools.html#how-do-i-get-the-old-version-back';
// HACK
//
// Extracting during build time avoids a temporarily invalid state for the inline target.

View File

@@ -73,6 +73,7 @@ export default class Store extends EventEmitter<{|
supportsNativeStyleEditor: [],
supportsProfiling: [],
supportsReloadAndProfile: [],
unsupportedRendererVersionDetected: [],
|}> {
_bridge: FrontendBridge;
@@ -125,6 +126,8 @@ export default class Store extends EventEmitter<{|
_supportsProfiling: boolean = false;
_supportsReloadAndProfile: boolean = false;
_unsupportedRendererVersionDetected: boolean = false;
// Total number of visible elements (within all roots).
// Used for windowing purposes.
_weightAcrossRoots: number = 0;
@@ -179,6 +182,10 @@ export default class Store extends EventEmitter<{|
'isNativeStyleEditorSupported',
this.onBridgeNativeStyleEditorSupported,
);
bridge.addListener(
'unsupportedRendererVersion',
this.onBridgeUnsupportedRendererVersion,
);
this._profilerStore = new ProfilerStore(bridge, this, isProfiling);
}
@@ -337,6 +344,10 @@ export default class Store extends EventEmitter<{|
return this._supportsReloadAndProfile && this._isBackendStorageAPISupported;
}
get unsupportedRendererVersionDetected(): boolean {
return this._unsupportedRendererVersionDetected;
}
containsElement(id: number): boolean {
return this._idToElement.get(id) != null;
}
@@ -1009,4 +1020,10 @@ export default class Store extends EventEmitter<{|
this.emit('supportsReloadAndProfile');
};
onBridgeUnsupportedRendererVersion = () => {
this._unsupportedRendererVersionDetected = true;
this.emit('unsupportedRendererVersionDetected');
};
}

View File

@@ -24,6 +24,7 @@ import ViewElementSourceContext from './Components/ViewElementSourceContext';
import {ProfilerContextController} from './Profiler/ProfilerContext';
import {ModalDialogContextController} from './ModalDialog';
import ReactLogo from './ReactLogo';
import UnsupportedVersionDialog from './UnsupportedVersionDialog';
import WarnIfLegacyBackendDetected from './WarnIfLegacyBackendDetected';
import styles from './DevTools.css';
@@ -51,6 +52,7 @@ export type Props = {|
showTabBar?: boolean,
store: Store,
warnIfLegacyBackendDetected?: boolean,
warnIfUnsupportedVersionDetected?: boolean,
viewElementSourceFunction?: ?ViewElementSource,
// This property is used only by the web extension target.
@@ -92,6 +94,7 @@ export default function DevTools({
showTabBar = false,
store,
warnIfLegacyBackendDetected = false,
warnIfUnsupportedVersionDetected = false,
viewElementSourceFunction,
}: Props) {
const [tab, setTab] = useState(defaultTab);
@@ -164,6 +167,7 @@ export default function DevTools({
</ViewElementSourceContext.Provider>
</SettingsContextController>
{warnIfLegacyBackendDetected && <WarnIfLegacyBackendDetected />}
{warnIfUnsupportedVersionDetected && <UnsupportedVersionDialog />}
</ModalDialogContextController>
</StoreContext.Provider>
</BridgeContext.Provider>

View File

@@ -0,0 +1,20 @@
.Row {
display: flex;
flex-direction: row;
align-items: center;
}
.Column {
display: flex;
flex-direction: column;
align-items: center;
}
.Title {
font-size: var(--font-size-sans-large);
margin-bottom: 0.5rem;
}
.ReleaseNotesLink {
color: var(--color-button-active);
}

View File

@@ -0,0 +1,83 @@
/**
* 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.
*
* @flow
*/
import React, {Fragment, useContext, useEffect, useState} from 'react';
import {unstable_batchedUpdates as batchedUpdates} from 'react-dom';
import {ModalDialogContext} from './ModalDialog';
import {StoreContext} from './context';
import {UNSUPPORTED_VERSION_URL} from 'react-devtools-shared/src/constants';
import styles from './UnsupportedVersionDialog.css';
type DAILOG_STATE = 'dialog-not-shown' | 'show-dialog' | 'dialog-shown';
export default function UnsupportedVersionDialog(_: {||}) {
const {dispatch} = useContext(ModalDialogContext);
const store = useContext(StoreContext);
const [state, setState] = useState<DAILOG_STATE>('dialog-not-shown');
useEffect(
() => {
if (state === 'dialog-not-shown') {
const showDialog = () => {
batchedUpdates(() => {
setState('show-dialog');
dispatch({
canBeDismissed: true,
type: 'SHOW',
content: <DialogContent />,
});
});
};
if (store.unsupportedRendererVersionDetected) {
showDialog();
} else {
store.addListener('unsupportedRendererVersionDetected', showDialog);
return () => {
store.removeListener(
'unsupportedRendererVersionDetected',
showDialog,
);
};
}
}
},
[state, store],
);
return null;
}
function DialogContent(_: {||}) {
return (
<Fragment>
<div className={styles.Row}>
<div>
<div className={styles.Title}>Unsupported React version detected</div>
<p>
This version of React DevTools supports React DOM v15+ and React
Native v61+.
</p>
<p>
In order to use DevTools with an older version of React, you'll need
to{' '}
<a
className={styles.ReleaseNotesLink}
target="_blank"
rel="noopener noreferrer"
href={UNSUPPORTED_VERSION_URL}>
install an older version of the extension
</a>.
</p>
</div>
</div>
</Fragment>
);
}

View File

@@ -57,6 +57,7 @@ inject('dist/app.js', () => {
browserTheme: 'light',
showTabBar: true,
warnIfLegacyBackendDetected: true,
warnIfUnsupportedVersionDetected: true,
}),
);
},

View File

@@ -12,6 +12,7 @@
* Fixed bug where Components panel was always empty for certain users. ([linshunghuang](https://github.com/linshunghuang) in [#16900](https://github.com/facebook/react/pull/16900))
* Fixed regression in DevTools editable hooks interface that caused primitive values to be shown as `undefined`. ([bvaughn](https://github.com/bvaughn) in [#16867](https://github.com/facebook/react/pull/16867))
* Fixed bug where DevTools showed stale values in props/state/hooks editing interface. ([bvaughn](https://github.com/bvaughn) in [#16878](https://github.com/facebook/react/pull/16878))
* Show unsupported version dialog with downgrade instructions. ([bvaughn](https://github.com/bvaughn) in [#16897](https://github.com/facebook/react/pull/16897))
</details>
## 4.1.0 (September 19, 2019)