mirror of
https://github.com/facebook/react.git
synced 2026-02-26 18:58:05 +00:00
222 lines
5.6 KiB
JavaScript
222 lines
5.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 React, {Fragment, useContext} from 'react';
|
|
import ProfilerStore from 'react-devtools-shared/src/devtools/ProfilerStore';
|
|
import {ProfilerContext} from './ProfilerContext';
|
|
import {formatDuration, formatTime} from './utils';
|
|
import {StoreContext} from '../context';
|
|
import Button from '../Button';
|
|
import ButtonIcon from '../ButtonIcon';
|
|
|
|
import styles from './SidebarSelectedFiberInfo.css';
|
|
|
|
export type Props = {||};
|
|
|
|
export default function SidebarSelectedFiberInfo(_: Props) {
|
|
const {profilerStore} = useContext(StoreContext);
|
|
const {
|
|
rootID,
|
|
selectCommitIndex,
|
|
selectedCommitIndex,
|
|
selectedFiberID,
|
|
selectedFiberName,
|
|
selectFiber,
|
|
} = useContext(ProfilerContext);
|
|
const {profilingCache} = profilerStore;
|
|
|
|
const commitIndices = profilingCache.getFiberCommits({
|
|
fiberID: ((selectedFiberID: any): number),
|
|
rootID: ((rootID: any): number),
|
|
});
|
|
|
|
const listItems = [];
|
|
let i = 0;
|
|
for (i = 0; i < commitIndices.length; i++) {
|
|
const commitIndex = commitIndices[i];
|
|
|
|
const {duration, timestamp} = profilerStore.getCommitData(
|
|
((rootID: any): number),
|
|
commitIndex,
|
|
);
|
|
|
|
listItems.push(
|
|
<button
|
|
key={commitIndex}
|
|
className={
|
|
selectedCommitIndex === commitIndex
|
|
? styles.CurrentCommit
|
|
: styles.Commit
|
|
}
|
|
onClick={() => selectCommitIndex(commitIndex)}>
|
|
{formatTime(timestamp)}s for {formatDuration(duration)}ms
|
|
</button>,
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Fragment>
|
|
<div className={styles.Toolbar}>
|
|
<div className={styles.Component}>
|
|
{selectedFiberName || 'Selected component'}
|
|
</div>
|
|
|
|
<Button
|
|
className={styles.IconButton}
|
|
onClick={() => selectFiber(null, null)}
|
|
title="Back to commit view">
|
|
<ButtonIcon type="close" />
|
|
</Button>
|
|
</div>
|
|
<div className={styles.Content}>
|
|
<WhatChanged
|
|
commitIndex={((selectedCommitIndex: any): number)}
|
|
fiberID={((selectedFiberID: any): number)}
|
|
profilerStore={profilerStore}
|
|
rootID={((rootID: any): number)}
|
|
/>
|
|
{listItems.length > 0 && (
|
|
<Fragment>
|
|
<label className={styles.Label}>Rendered at</label>: {listItems}
|
|
</Fragment>
|
|
)}
|
|
{listItems.length === 0 && (
|
|
<div>Did not render during this profiling session.</div>
|
|
)}
|
|
</div>
|
|
</Fragment>
|
|
);
|
|
}
|
|
|
|
type WhatChangedProps = {|
|
|
commitIndex: number | null,
|
|
fiberID: number,
|
|
profilerStore: ProfilerStore,
|
|
rootID: number,
|
|
|};
|
|
|
|
function WhatChanged({
|
|
commitIndex,
|
|
fiberID,
|
|
profilerStore,
|
|
rootID,
|
|
}: WhatChangedProps) {
|
|
// TRICKY
|
|
// Handle edge case where no commit is selected because of a min-duration filter update.
|
|
// If the commit index is null, suspending for data below would throw an error.
|
|
// TODO (ProfilerContext) This check should not be necessary.
|
|
if (commitIndex === null) {
|
|
return null;
|
|
}
|
|
|
|
const {changeDescriptions} = profilerStore.getCommitData(
|
|
((rootID: any): number),
|
|
commitIndex,
|
|
);
|
|
if (changeDescriptions === null) {
|
|
return null;
|
|
}
|
|
|
|
const changeDescription = changeDescriptions.get(fiberID);
|
|
if (changeDescription == null) {
|
|
return null;
|
|
}
|
|
|
|
if (changeDescription.isFirstMount) {
|
|
return (
|
|
<div className={styles.WhatChanged}>
|
|
<label className={styles.Label}>Why did this render?</label>
|
|
<div className={styles.WhatChangedItem}>
|
|
This is the first time the component rendered.
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const changes = [];
|
|
|
|
if (changeDescription.context === true) {
|
|
changes.push(
|
|
<div key="context" className={styles.WhatChangedItem}>
|
|
• Context changed
|
|
</div>,
|
|
);
|
|
} else if (
|
|
typeof changeDescription.context === 'object' &&
|
|
changeDescription.context !== null &&
|
|
changeDescription.context.length !== 0
|
|
) {
|
|
changes.push(
|
|
<div key="context" className={styles.WhatChangedItem}>
|
|
• Context changed:
|
|
{changeDescription.context.map(key => (
|
|
<span key={key} className={styles.WhatChangedKey}>
|
|
{key}
|
|
</span>
|
|
))}
|
|
</div>,
|
|
);
|
|
}
|
|
|
|
if (changeDescription.didHooksChange) {
|
|
changes.push(
|
|
<div key="hooks" className={styles.WhatChangedItem}>
|
|
• Hooks changed
|
|
</div>,
|
|
);
|
|
}
|
|
|
|
if (
|
|
changeDescription.props !== null &&
|
|
changeDescription.props.length !== 0
|
|
) {
|
|
changes.push(
|
|
<div key="props" className={styles.WhatChangedItem}>
|
|
• Props changed:
|
|
{changeDescription.props.map(key => (
|
|
<span key={key} className={styles.WhatChangedKey}>
|
|
{key}
|
|
</span>
|
|
))}
|
|
</div>,
|
|
);
|
|
}
|
|
|
|
if (
|
|
changeDescription.state !== null &&
|
|
changeDescription.state.length !== 0
|
|
) {
|
|
changes.push(
|
|
<div key="state" className={styles.WhatChangedItem}>
|
|
• State changed:
|
|
{changeDescription.state.map(key => (
|
|
<span key={key} className={styles.WhatChangedKey}>
|
|
{key}
|
|
</span>
|
|
))}
|
|
</div>,
|
|
);
|
|
}
|
|
|
|
if (changes.length === 0) {
|
|
changes.push(
|
|
<div key="nothing" className={styles.WhatChangedItem}>
|
|
The parent component rendered.
|
|
</div>,
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className={styles.WhatChanged}>
|
|
<label className={styles.Label}>Why did this render?</label>
|
|
{changes}
|
|
</div>
|
|
);
|
|
}
|