[DevTools] Don't call Hooks conditionally (#34644)

This commit is contained in:
Sebastian "Sebbie" Silbermann 2025-09-29 15:15:09 +02:00 committed by GitHub
parent dce1f6cd5d
commit 2bbb7be0e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 40 deletions

View File

@ -8,6 +8,7 @@
*/ */
import type {SchedulingEvent} from 'react-devtools-timeline/src/types'; import type {SchedulingEvent} from 'react-devtools-timeline/src/types';
import type {ReactFunctionLocation} from 'shared/ReactTypes';
import * as React from 'react'; import * as React from 'react';
import Button from '../Button'; import Button from '../Button';
@ -27,6 +28,28 @@ import styles from './SidebarEventInfo.css';
export type Props = {}; export type Props = {};
type FunctionLocationProps = {
location: ReactFunctionLocation,
displayName: string,
};
function FunctionLocation({location, displayName}: FunctionLocationProps) {
// TODO: We should support symbolication here as well, but
// symbolicating the whole stack can be expensive
const [canViewSource, viewSource] = useOpenResource(location, null);
return (
<li>
<Button
className={
canViewSource ? styles.ClickableSource : styles.UnclickableSource
}
disabled={!canViewSource}
onClick={viewSource}>
{displayName}
</Button>
</li>
);
}
type SchedulingEventProps = { type SchedulingEventProps = {
eventInfo: SchedulingEvent, eventInfo: SchedulingEvent,
}; };
@ -74,25 +97,12 @@ function SchedulingEventInfo({eventInfo}: SchedulingEventProps) {
); );
} }
// TODO: We should support symbolication here as well, but
// symbolicating the whole stack can be expensive
const [canViewSource, viewSource] = useOpenResource(
location,
null,
);
return ( return (
<li key={index}> <FunctionLocation
<Button key={index}
className={ displayName={displayName}
canViewSource location={location}
? styles.ClickableSource />
: styles.UnclickableSource
}
disabled={!canViewSource}
onClick={viewSource}>
{displayName}
</Button>
</li>
); );
}, },
)} )}

View File

@ -39,28 +39,6 @@ function SuspenseTimelineInput() {
const min = 0; const min = 0;
const max = timeline.length > 0 ? timeline.length - 1 : 0; const max = timeline.length > 0 ? timeline.length - 1 : 0;
if (rootID === null) {
return (
<div className={styles.SuspenseTimelineInput}>No root selected.</div>
);
}
if (!store.supportsTogglingSuspense(rootID)) {
return (
<div className={styles.SuspenseTimelineInput}>
Can't step through Suspense in production apps.
</div>
);
}
if (timeline.length === 0) {
return (
<div className={styles.SuspenseTimelineInput}>
Root contains no Suspense nodes.
</div>
);
}
function switchSuspenseNode(nextTimelineIndex: number) { function switchSuspenseNode(nextTimelineIndex: number) {
const nextSelectedSuspenseID = timeline[nextTimelineIndex]; const nextSelectedSuspenseID = timeline[nextTimelineIndex];
highlightHostInstance(nextSelectedSuspenseID); highlightHostInstance(nextSelectedSuspenseID);
@ -175,6 +153,28 @@ function SuspenseTimelineInput() {
}; };
}, [playing]); }, [playing]);
if (rootID === null) {
return (
<div className={styles.SuspenseTimelineInput}>No root selected.</div>
);
}
if (!store.supportsTogglingSuspense(rootID)) {
return (
<div className={styles.SuspenseTimelineInput}>
Can't step through Suspense in production apps.
</div>
);
}
if (timeline.length === 0) {
return (
<div className={styles.SuspenseTimelineInput}>
Root contains no Suspense nodes.
</div>
);
}
return ( return (
<> <>
<Button <Button