Skip to content

Commit 1b81585

Browse files
smeijerphongphongg
andauthored
feat: add support for SSR (#8)
Co-authored-by: Phong Chu <58473133+chucamphong@users.noreply.github.com>
1 parent 02fd810 commit 1b81585

File tree

3 files changed

+62
-4
lines changed

3 files changed

+62
-4
lines changed

.changeset/fresh-monkeys-yell.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'spin-delay': major
3+
---
4+
5+
We now support spinner initialization from the server (SSR). When the `loading` prop is `true` due to server-side rendering, the spinner will be shown immediately. You can opt-out of this behavior by setting the `ssr` option to `false`.
6+
7+
```tsx
8+
import { useSpinDelay } from 'spin-delay';
9+
10+
const spin = useSpinDelay(loading, {
11+
ssr: false, // defaults to true
12+
});
13+
```

src/index.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,58 @@
11
import { useState, useEffect, useRef } from 'react';
22

33
interface SpinDelayOptions {
4+
/**
5+
* The delay in milliseconds before the spinner is displayed.
6+
* @default 500
7+
*/
48
delay?: number;
9+
/**
10+
* The minimum duration in milliseconds the spinner is displayed.
11+
* @default 200
12+
*/
513
minDuration?: number;
14+
/**
15+
* Whether to enable the spinner on the server side. If true, `delay` will be
16+
* ignored, and the spinner will be shown immediately if `loading` is true.
17+
* @default true
18+
*/
19+
ssr?: boolean;
620
}
721

822
type State = 'IDLE' | 'DELAY' | 'DISPLAY' | 'EXPIRE';
923

1024
export const defaultOptions = {
1125
delay: 500,
1226
minDuration: 200,
27+
ssr: true,
1328
};
1429

30+
function useIsSSR() {
31+
const [isSSR, setIsSSR] = useState(true);
32+
33+
useEffect(() => {
34+
setIsSSR(false);
35+
}, []);
36+
37+
return isSSR;
38+
}
39+
1540
export function useSpinDelay(
1641
loading: boolean,
1742
options?: SpinDelayOptions,
1843
): boolean {
1944
options = Object.assign({}, defaultOptions, options);
2045

21-
const [state, setState] = useState<State>('IDLE');
46+
const isSSR = useIsSSR();
47+
const initialState = options.ssr && isSSR && loading ? 'DISPLAY' : 'IDLE';
48+
const [state, setState] = useState<State>(initialState);
2249
const timeout = useRef(null);
2350

2451
useEffect(() => {
25-
if (loading && state === 'IDLE') {
52+
if (loading && (state === 'IDLE' || isSSR)) {
2653
clearTimeout(timeout.current);
2754

55+
const delay = isSSR ? 0 : options.delay;
2856
timeout.current = setTimeout(() => {
2957
if (!loading) {
3058
return setState('IDLE');
@@ -35,9 +63,11 @@ export function useSpinDelay(
3563
}, options.minDuration);
3664

3765
setState('DISPLAY');
38-
}, options.delay);
66+
}, delay);
3967

40-
setState('DELAY');
68+
if (!isSSR) {
69+
setState('DELAY');
70+
}
4171
}
4272

4373
if (!loading && state !== 'DISPLAY') {

types/index.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11
interface SpinDelayOptions {
2+
/**
3+
* The delay in milliseconds before the spinner is displayed.
4+
* @default 500
5+
*/
26
delay?: number;
7+
/**
8+
* The minimum duration in milliseconds the spinner is displayed.
9+
* @default 200
10+
*/
311
minDuration?: number;
12+
/**
13+
* Whether to enable the spinner on the server side. If true, `delay` will be
14+
* ignored, and the spinner will be shown immediately if `loading` is true.
15+
* @default true
16+
*/
17+
ssr?: boolean;
418
}
519
export declare const defaultOptions: {
620
delay: number;
721
minDuration: number;
22+
ssr: true;
823
};
924
export declare function useSpinDelay(
1025
loading: boolean,

0 commit comments

Comments
 (0)