Skip to content

Commit ce8e555

Browse files
committed
refactor: make it harder to misuse render cache
1 parent 638ccf5 commit ce8e555

File tree

1 file changed

+10
-19
lines changed

1 file changed

+10
-19
lines changed

site/src/components/Spinner/Spinner.tsx

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
2-
* @file This component was inspired by Radix's Spinner component and developed
3-
* using help from Vercel's V0.
2+
* @file This component was inspired by Radix's Spinner component. The animation
3+
* settings were developed using Vercel's v0.
44
*
55
* @see {@link https://www.radix-ui.com/themes/docs/components/spinner}
66
* @see {@link https://v0.dev/}
@@ -128,9 +128,9 @@ export const Spinner: FC<SpinnerProps> = ({
128128
*/}
129129
{(!showSpinner || !unmountChildrenWhileLoading) && (
130130
<>
131-
<span className={showSpinner ? "sr-only" : "hidden"}>
132-
This content is loading:{" "}
133-
</span>
131+
{showSpinner && (
132+
<span className="sr-only">This content is loading: </span>
133+
)}
134134
<span className={showSpinner ? "sr-only" : "inline"}>{children}</span>
135135
</>
136136
)}
@@ -156,29 +156,20 @@ function useShowSpinner(loading: boolean, spinnerDelayMs: number): boolean {
156156
/**
157157
* Doing a bunch of mid-render state syncs to minimize risks of UI tearing
158158
* during re-renders. It's ugly, but it's what the React team officially
159-
* recommends (even though this specific case is extra nasty).
159+
* recommends.
160160
* @see {@link https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes}
161-
*
162-
* Be very careful with this logic; React only bails out of redundant state
163-
* updates if they happen outside of a render. Inside a render, if you keep
164-
* calling a state dispatch, you will get an infinite render loop, no matter
165-
* what value you dispatch. There must be a "base case" in the render path
166-
* that causes state dispatches to stop entirely so that React can move on
167-
* to the next component in the Fiber subtree
168161
*/
169162
const [delayLapsed, setDelayLapsed] = useState(safeDelay === 0);
170-
const [renderCache, setRenderCache] = useState({ loading, safeDelay });
171-
const canResetLapseOnRerender =
172-
delayLapsed && !loading && loading !== renderCache.loading;
163+
const [cachedDelay, setCachedDelay] = useState(safeDelay);
164+
const canResetLapseOnRerender = delayLapsed && !loading;
173165
if (canResetLapseOnRerender) {
174166
setDelayLapsed(false);
175-
setRenderCache((current) => ({ ...current, loading }));
176167
}
177168
const delayWasRemovedOnRerender =
178-
!delayLapsed && safeDelay === 0 && renderCache.safeDelay !== safeDelay;
169+
!delayLapsed && safeDelay === 0 && safeDelay !== cachedDelay;
179170
if (delayWasRemovedOnRerender) {
180171
setDelayLapsed(true);
181-
setRenderCache((current) => ({ ...current, safeDelay }));
172+
setCachedDelay(safeDelay);
182173
}
183174
useEffect(() => {
184175
if (safeDelay === 0) {

0 commit comments

Comments
 (0)