mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
151 lines
4.6 KiB
JavaScript
151 lines
4.6 KiB
JavaScript
/**
|
|
* 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 type {DataResource} from './createDataResourceFromImportedFile';
|
|
import type {ViewState} from './types';
|
|
|
|
import * as React from 'react';
|
|
import {
|
|
Suspense,
|
|
useContext,
|
|
useDeferredValue,
|
|
useLayoutEffect,
|
|
useRef,
|
|
useState,
|
|
} from 'react';
|
|
import {SettingsContext} from 'react-devtools-shared/src/devtools/views/Settings/SettingsContext';
|
|
import {updateColorsToMatchTheme} from './content-views/constants';
|
|
import {SchedulingProfilerContext} from './SchedulingProfilerContext';
|
|
import ImportButton from './ImportButton';
|
|
import CanvasPage from './CanvasPage';
|
|
|
|
import styles from './SchedulingProfiler.css';
|
|
|
|
export function SchedulingProfiler(_: {||}) {
|
|
const {
|
|
importSchedulingProfilerData,
|
|
schedulingProfilerData,
|
|
viewState,
|
|
} = useContext(SchedulingProfilerContext);
|
|
|
|
const ref = useRef(null);
|
|
|
|
// HACK: Canvas rendering uses an imperative API,
|
|
// but DevTools colors are stored in CSS variables (see root.css and SettingsContext).
|
|
// When the theme changes, we need to trigger update the imperative colors and re-draw the Canvas.
|
|
const {theme} = useContext(SettingsContext);
|
|
// HACK: SettingsContext also uses a useLayoutEffect to update styles;
|
|
// make sure the theme context in SettingsContext updates before this code.
|
|
const deferredTheme = useDeferredValue(theme);
|
|
// HACK: Schedule a re-render of the Canvas once colors have been updated.
|
|
// The easiest way to guarangee this happens is to recreate the inner Canvas component.
|
|
const [key, setKey] = useState<string>(theme);
|
|
useLayoutEffect(() => {
|
|
const pollForTheme = () => {
|
|
if (updateColorsToMatchTheme(((ref.current: any): HTMLDivElement))) {
|
|
clearInterval(intervalID);
|
|
setKey(deferredTheme);
|
|
}
|
|
};
|
|
|
|
const intervalID = setInterval(pollForTheme, 50);
|
|
|
|
return () => {
|
|
clearInterval(intervalID);
|
|
};
|
|
}, [deferredTheme]);
|
|
|
|
return (
|
|
<div className={styles.Content} ref={ref}>
|
|
{schedulingProfilerData ? (
|
|
<Suspense fallback={<ProcessingData />}>
|
|
<DataResourceComponent
|
|
dataResource={schedulingProfilerData}
|
|
key={key}
|
|
onFileSelect={importSchedulingProfilerData}
|
|
viewState={viewState}
|
|
/>
|
|
</Suspense>
|
|
) : (
|
|
<Welcome onFileSelect={importSchedulingProfilerData} />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const Welcome = ({onFileSelect}: {|onFileSelect: (file: File) => void|}) => (
|
|
<ol className={styles.WelcomeInstructionsList}>
|
|
<li className={styles.WelcomeInstructionsListItem}>
|
|
Open a website that's built with the
|
|
<a
|
|
className={styles.WelcomeInstructionsListItemLink}
|
|
href="https://reactjs.org/link/profiling"
|
|
rel="noopener noreferrer"
|
|
target="_blank">
|
|
profiling build of ReactDOM
|
|
</a>
|
|
(version 18 or newer).
|
|
</li>
|
|
<li className={styles.WelcomeInstructionsListItem}>
|
|
Open the "Performance" tab in Chrome and record some performance data.
|
|
</li>
|
|
<li className={styles.WelcomeInstructionsListItem}>
|
|
Click the "Save profile..." button in Chrome to export the data.
|
|
</li>
|
|
<li className={styles.WelcomeInstructionsListItem}>
|
|
Import the data into the profiler:
|
|
<br />
|
|
<ImportButton onFileSelect={onFileSelect}>
|
|
<span className={styles.ImportButtonLabel}>Import</span>
|
|
</ImportButton>
|
|
</li>
|
|
</ol>
|
|
);
|
|
|
|
const ProcessingData = () => (
|
|
<div className={styles.EmptyStateContainer}>
|
|
<div className={styles.Header}>Processing data...</div>
|
|
<div className={styles.Row}>This should only take a minute.</div>
|
|
</div>
|
|
);
|
|
|
|
const CouldNotLoadProfile = ({error, onFileSelect}) => (
|
|
<div className={styles.EmptyStateContainer}>
|
|
<div className={styles.Header}>Could not load profile</div>
|
|
{error.message && (
|
|
<div className={styles.Row}>
|
|
<div className={styles.ErrorMessage}>{error.message}</div>
|
|
</div>
|
|
)}
|
|
<div className={styles.Row}>
|
|
Try importing
|
|
<ImportButton onFileSelect={onFileSelect} />
|
|
another Chrome performance profile.
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
const DataResourceComponent = ({
|
|
dataResource,
|
|
onFileSelect,
|
|
viewState,
|
|
}: {|
|
|
dataResource: DataResource,
|
|
onFileSelect: (file: File) => void,
|
|
viewState: ViewState,
|
|
|}) => {
|
|
const dataOrError = dataResource.read();
|
|
if (dataOrError instanceof Error) {
|
|
return (
|
|
<CouldNotLoadProfile error={dataOrError} onFileSelect={onFileSelect} />
|
|
);
|
|
}
|
|
return <CanvasPage profilerData={dataOrError} viewState={viewState} />;
|
|
};
|