mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
DevTools shows unsupported renderer version dialog (#16897)
* DevTools shows unsupported renderer version dialog * Optimistic CHANGELOG udpate
This commit is contained in:
@@ -161,7 +161,7 @@ function createPanelIfReactLoaded() {
|
||||
overrideTab,
|
||||
profilerPortalContainer,
|
||||
showTabBar: false,
|
||||
showWelcomeToTheNewDevToolsDialog: true,
|
||||
warnIfUnsupportedVersionDetected: true,
|
||||
store,
|
||||
viewElementSourceFunction,
|
||||
}),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
1
packages/react-devtools-shared/src/bridge.js
vendored
1
packages/react-devtools-shared/src/bridge.js
vendored
@@ -83,6 +83,7 @@ type BackendEvents = {|
|
||||
stopInspectingNative: [boolean],
|
||||
syncSelectionFromNativeElementsPanel: [],
|
||||
syncSelectionToNativeElementsPanel: [],
|
||||
unsupportedRendererVersion: [RendererID],
|
||||
|
||||
// React Native style editor plug-in.
|
||||
isNativeStyleEditorSupported: [
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
83
packages/react-devtools-shared/src/devtools/views/UnsupportedVersionDialog.js
vendored
Normal file
83
packages/react-devtools-shared/src/devtools/views/UnsupportedVersionDialog.js
vendored
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -57,6 +57,7 @@ inject('dist/app.js', () => {
|
||||
browserTheme: 'light',
|
||||
showTabBar: true,
|
||||
warnIfLegacyBackendDetected: true,
|
||||
warnIfUnsupportedVersionDetected: true,
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user