Skip to content

Commit 9d10111

Browse files
committed
feat: manual control of useSimulatePorgress startup
1 parent 072d19b commit 9d10111

File tree

3 files changed

+61
-39
lines changed

3 files changed

+61
-39
lines changed

__test__/use-simulate-progress.test.ts

+31-26
Original file line numberDiff line numberDiff line change
@@ -6,70 +6,75 @@ import { useSimulateProgress } from '../src';
66
jest.useFakeTimers();
77

88
describe('useSimulateProgress', () => {
9-
it('should update progress periodically and reach 100%', () => {
9+
test('should not start progress automatically', () => {
1010
const mockCallback = jest.fn();
1111
const { result } = renderHook(() =>
1212
useSimulateProgress(1000, mockCallback),
1313
);
1414

15-
// Initial progress should be 0
16-
expect(result.current).toBe(0);
15+
// Progress should initially be 0
16+
expect(result.current[0]).toBe(0);
17+
18+
// Progress should not change before startProgress is called
19+
act(() => {
20+
jest.advanceTimersByTime(500); // Fast-forward 500ms
21+
});
22+
expect(result.current[0]).toBe(0);
23+
});
24+
25+
test('should update progress when startProgress is called', () => {
26+
const mockCallback = jest.fn();
27+
const { result } = renderHook(() =>
28+
useSimulateProgress(1000, mockCallback),
29+
);
30+
31+
// Call startProgress to trigger the progress
32+
act(() => {
33+
result.current[1](); // Call startProgress
34+
});
1735

1836
// Fast-forward the timer, simulating time passing
1937
act(() => {
20-
jest.advanceTimersByTime(250);
38+
jest.advanceTimersByTime(250); // Fast-forward 250ms
2139
});
2240

2341
// Progress should update to 25%
24-
expect(result.current).toBe(25);
42+
expect(result.current[0]).toBe(25);
2543

2644
act(() => {
2745
jest.advanceTimersByTime(500); // Fast-forward another 500ms
2846
});
2947

3048
// Progress should update to 75%
31-
expect(result.current).toBe(75);
49+
expect(result.current[0]).toBe(75);
3250

3351
act(() => {
3452
jest.advanceTimersByTime(250); // Finish the remaining time
3553
});
3654

3755
// Progress should be 100%, and callback should be called
38-
expect(result.current).toBe(100);
56+
expect(result.current[0]).toBe(100);
3957
expect(mockCallback).toHaveBeenCalledTimes(1);
4058
});
4159

42-
it('should not call callback if progress is less than 100%', () => {
60+
test('should clear interval when unmounted', () => {
4361
const mockCallback = jest.fn();
44-
const { result } = renderHook(() =>
62+
const { result, unmount } = renderHook(() =>
4563
useSimulateProgress(1000, mockCallback),
4664
);
4765

48-
// Fast-forward the timer to 50%
66+
// Call startProgress to trigger the progress
4967
act(() => {
50-
jest.advanceTimersByTime(500); // Fast-forward 500ms
68+
result.current[1](); // Call startProgress
5169
});
5270

53-
// Progress should be 50%
54-
expect(result.current).toBe(50);
55-
56-
// Callback should not be called
57-
expect(mockCallback).not.toHaveBeenCalled();
58-
});
59-
60-
test('should clear interval when unmounted', () => {
61-
const mockCallback = jest.fn();
62-
const { result, unmount } = renderHook(() =>
63-
useSimulateProgress(1000, mockCallback),
64-
);
65-
6671
// Fast-forward the timer halfway
6772
act(() => {
6873
jest.advanceTimersByTime(500);
6974
});
7075

7176
// Progress should be 50%
72-
expect(result.current).toBe(50);
77+
expect(result.current[0]).toBe(50);
7378

7479
// Unmount the component
7580
unmount();
@@ -80,7 +85,7 @@ describe('useSimulateProgress', () => {
8085
});
8186

8287
// Progress should not update further
83-
expect(result.current).toBe(50);
88+
expect(result.current[0]).toBe(50);
8489

8590
// Callback should not be called
8691
expect(mockCallback).not.toHaveBeenCalled();

docs/use-simulate-progress.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import { useSimulateProgress } from '@mints/hooks';
99

1010
const Example = () => {
11-
const progress = useSimulateProgress(duration, () => {
11+
const [progress, startProgress] = useSimulateProgress(duration, () => {
1212
console.log('Progress complete!');
1313
});
1414

@@ -17,6 +17,7 @@ const Example = () => {
1717
className="progress-bar"
1818
style={{ width: '100%', background: '#e0e0e0', height: '30px' }}
1919
>
20+
<div onClick={startProgress}>Start Progress</div>
2021
<div
2122
style={{
2223
width: `${progress}%`,
@@ -36,8 +37,10 @@ const Example = () => {
3637
## API
3738

3839
```typescript
40+
type func = (...args: any[]) => void;
41+
3942
useSimulateProgress = (
4043
duration: number,
41-
onComplete: () => void,
42-
): number
44+
onComplete: func,
45+
): [number, func]
4346
```

src/use-simulate-progress.ts

+24-10
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,39 @@
1-
import { useState, useEffect } from 'react';
1+
import { useState, useEffect, useRef } from 'react';
2+
3+
type func = (...args: any[]) => void;
24

35
export const useSimulateProgress = (
46
duration: number,
5-
onComplete: () => void,
6-
) => {
7+
onComplete: func,
8+
): [number, func] => {
79
const [progress, setProgress] = useState(0);
10+
const intervalRef = useRef<any>(null);
11+
12+
const startProgress: func = (...args) => {
13+
if (intervalRef.current) return;
814

9-
useEffect(() => {
1015
let progressValue = 0;
11-
const interval = setInterval(() => {
16+
intervalRef.current = setInterval(() => {
1217
progressValue += 5;
1318
setProgress(progressValue);
1419

1520
if (progressValue >= 100) {
16-
clearInterval(interval);
17-
onComplete();
21+
clearInterval(intervalRef.current);
22+
intervalRef.current = null;
23+
onComplete(...args);
1824
}
1925
}, duration / 20);
26+
};
2027

21-
return () => clearInterval(interval);
22-
}, [duration, onComplete]);
28+
useEffect(() => {
29+
return () => {
30+
if (intervalRef.current) {
31+
clearInterval(intervalRef.current);
32+
}
33+
};
34+
}, []);
2335

24-
return progress;
36+
return [progress, startProgress];
2537
};
38+
39+
export default useSimulateProgress;

0 commit comments

Comments
 (0)