From f1222f76521fa7645badaa0c972ad4b2b1dc0b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 12 Aug 2025 21:42:24 -0400 Subject: [PATCH 1/2] [Fiber] Don't bind retry listener if it's in the cache (#34183) This did an unnecessary bind allocation even if there's cache hit. --- packages/react-reconciler/src/ReactFiberCommitWork.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index ba012a67d09..b6716506a04 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -1894,7 +1894,6 @@ function attachSuspenseRetryListeners( const retryCache = getRetryCache(finishedWork); wakeables.forEach(wakeable => { // Memoize using the boundary fiber to prevent redundant listeners. - const retry = resolveRetryWakeable.bind(null, finishedWork, wakeable); if (!retryCache.has(wakeable)) { retryCache.add(wakeable); @@ -1911,6 +1910,7 @@ function attachSuspenseRetryListeners( } } + const retry = resolveRetryWakeable.bind(null, finishedWork, wakeable); wakeable.then(retry, retry); } }); From 14c50e344c2f639a9e08cc03b16cc7fc6c1d194a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 12 Aug 2025 23:10:31 -0400 Subject: [PATCH 2/2] [DevTools] Use Visually Lighter Skeletons (#34185) The skeletons right now are too jarring because they're visually heavier than the content that comes in later. This makes them draw attention to themselves as flashing things. A good skeleton and loading indicator should ideally start as invisible as possible and then gradually become more visible the longer time passes so that if it loads quickly then it was never much visible at all. Even at its max it should never be heavier weight than the final content so that it visually reverts into lesser. Another rule of thumb is that it should be as close as possible to the final content in size but if it's unknown it should always be smaller than the final content so that the content grows into its slot rather than the slot contracting. This makes the skeleton fade from invisible into the dimmest color just as a subtle hint that something is still loading. I also added a missing skeleton since the stack traces in rendered by can now suspend while source mapping. The other tweak I did is use disabled buttons in all the cases where we load the ability to enable a button. This is more subtle and if you hover over you can see why it's still disabled. Rather than flashing the button each time you change element. --- .../views/Components/InspectedElement.js | 20 +++--- .../Components/InspectedElementSourcePanel.js | 7 ++- .../views/Components/InspectedElementView.css | 4 ++ .../views/Components/InspectedElementView.js | 63 ++++++++++--------- .../InspectedElementViewSourceButton.js | 8 ++- .../devtools/views/Components/Skeleton.css | 4 +- .../views/Editor/OpenInEditorButton.js | 24 ++++++- 7 files changed, 84 insertions(+), 46 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElement.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElement.js index 7b19908cc8c..fd068c0ad18 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElement.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElement.js @@ -24,7 +24,6 @@ import FetchFileWithCachingContext from './FetchFileWithCachingContext'; import {symbolicateSourceWithCache} from 'react-devtools-shared/src/symbolicateSource'; import OpenInEditorButton from './OpenInEditorButton'; import InspectedElementViewSourceButton from './InspectedElementViewSourceButton'; -import Skeleton from './Skeleton'; import useEditorURL from '../useEditorURL'; import styles from './InspectedElement.css'; @@ -203,7 +202,9 @@ export default function InspectedElementWrapper(_: Props): React.Node { } return ( -
+
{strictModeBadge} @@ -232,13 +233,11 @@ export default function InspectedElementWrapper(_: Props): React.Node { !!editorURL && source != null && symbolicatedSourcePromise != null && ( - }> - - + )} {canToggleError && ( @@ -294,9 +293,6 @@ export default function InspectedElementWrapper(_: Props): React.Node { {inspectedElement !== null && symbolicatedSourcePromise != null && (
source
- }> + + + + }>
rendered by
- - {showStack ? : null} - {showOwnersList && - owners?.map(owner => ( - - - {owner.stack != null && owner.stack.length > 0 ? ( - - ) : null} - - ))} - - {rootType !== null && ( -
{rootType}
- )} - {rendererLabel !== null && ( -
{rendererLabel}
- )} + + +
+ }> + {showStack ? : null} + {showOwnersList && + owners?.map(owner => ( + + + {owner.stack != null && owner.stack.length > 0 ? ( + + ) : null} + + ))} + + {rootType !== null && ( +
{rootType}
+ )} + {rendererLabel !== null && ( +
{rendererLabel}
+ )} +
)} diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementViewSourceButton.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementViewSourceButton.js index 23d4cf96c82..ee2fbe6c4d2 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementViewSourceButton.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementViewSourceButton.js @@ -11,7 +11,6 @@ import * as React from 'react'; import ButtonIcon from '../ButtonIcon'; import Button from '../Button'; -import Skeleton from './Skeleton'; import type {ReactFunctionLocation} from 'shared/ReactTypes'; @@ -27,7 +26,12 @@ function InspectedElementViewSourceButton({ symbolicatedSourcePromise, }: Props): React.Node { return ( - }> + + + + }> + + Loading source maps... + + }> + + + ); +} + export default OpenInEditorButton;