Skip to content

Commit 3e0db15

Browse files
committed
docs: rewrite docs for clarity again
1 parent a69d576 commit 3e0db15

File tree

1 file changed

+24
-18
lines changed

1 file changed

+24
-18
lines changed

site/src/components/Spinner/Spinner.tsx

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ type SpinnerProps = Readonly<
3131
loading: boolean;
3232

3333
/**
34-
* Indicates whether the children prop should be unmounted during
35-
* a loading state. Defaults to false - unmounting HTML elements
34+
* Indicates whether the `children` prop should be unmounted during
35+
* a loading state. Defaults to `false` - unmounting HTML elements
3636
* like form controls can lead to invalid HTML, so this prop should
3737
* be used with care and only if it prevents render performance
3838
* issues.
@@ -42,17 +42,22 @@ type SpinnerProps = Readonly<
4242
/**
4343
* Specifies whether there should be a delay before the spinner
4444
* appears on screen. If not specified, the spinner always appears
45-
* immediately.
45+
* immediately when `loading` is true.
4646
*
47-
* Can help avoid page flickering issues. (e.g., You have a modal
48-
* that takes a moment to close, and it has Spinner content inside
49-
* it. The user triggers a loading transition, and you want to show
50-
* the spinner at some point if a transition takes long enough, but
51-
* if the spinner mounting and modal closing happen in too quick of
52-
* a succession, the UI looks janky. So even though you might flip
53-
* the loading state immediately, you want to wait a second to show
54-
* it in case the modal can close quickly enough. It's lying to the
55-
* user in a way that makes the UI feel more polished.)
47+
* Can help avoid page flickering issues. Example:
48+
* 1. You have a modal that takes a moment to close, and it has
49+
* Spinner content inside it.
50+
* 2. The user triggers a loading transition, and you want to show
51+
* the spinner at some point, especially if the transition takes
52+
* long enough.
53+
* 3. The problem is, if the spinner mounting and modal closing
54+
* happen in quick enough succession, the user will see a brief
55+
* spinner flicker before the modal closes, making the UI appear
56+
* janky, even though it is accurately modeling the state of the
57+
* application.
58+
* 4. The solution, then, to keep the UI feeling polished, is to lie
59+
* to the user and only show the loading state if some
60+
* pre-determined period has lapsed.
5661
*/
5762
spinnerDelayMs?: number;
5863
}
@@ -128,8 +133,9 @@ export const Spinner: FC<SpinnerProps> = ({
128133
};
129134

130135
// Splitting off logic into custom hook so that we can abstract away the chaos
131-
// of handling Spinner's re-render logic. Not worried about overhead; a lot of
132-
// browsers should be able to inline this function call
136+
// of handling Spinner's re-render logic. The result is a simple boolean, but
137+
// the steps to calculate that boolean accurately while avoiding re-render
138+
// issues got a little heady
133139
function useShowSpinner(loading: boolean, spinnerDelayMs: number): boolean {
134140
// Disallow negative timeout values and fractional values, but also round
135141
// the delay down if it's small enough that it might as well be immediate
@@ -147,13 +153,13 @@ function useShowSpinner(loading: boolean, spinnerDelayMs: number): boolean {
147153
// updates if they happen outside of a render. Inside a render, if you keep
148154
// calling a state dispatch, you will get an infinite render loop, no matter
149155
// what the value you dispatch. There must be a "base case" in the render
150-
// path that causes state dispatches to stop eventually so that React can
151-
// move on to the next component in the tree
156+
// path that causes state dispatches to stop entirely so that React can
157+
// move on to the next component in the Fiber subtree
152158
const [delayLapsed, setDelayLapsed] = useState(safeDelay === 0);
153159
const [renderCache, setRenderCache] = useState({ loading, safeDelay });
154-
const resetOnRerender =
160+
const canResetLapseOnRerender =
155161
delayLapsed && !loading && loading !== renderCache.loading;
156-
if (resetOnRerender) {
162+
if (canResetLapseOnRerender) {
157163
setDelayLapsed(false);
158164
setRenderCache((current) => ({ ...current, loading }));
159165
}

0 commit comments

Comments
 (0)