Skip to content

Commit 072d19b

Browse files
committed
feat: add a new hook useSimulateProgress
1 parent d251624 commit 072d19b

5 files changed

+158
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { useRequest } from '@mints/hooks';
3838
- [useDebounce](./docs/use-debounce.md)
3939
- [useToggle](./docs/use-toggle.md)
4040
- [useLocalStorage](./docs/use-localstorage.md)
41+
- [useSimulateProgress](./docs/use-simulate-progress.md)
4142

4243
## 🌐 LICENSE
4344

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { renderHook, act } from '@testing-library/react';
2+
3+
import { useSimulateProgress } from '../src';
4+
5+
// Mock timers
6+
jest.useFakeTimers();
7+
8+
describe('useSimulateProgress', () => {
9+
it('should update progress periodically and reach 100%', () => {
10+
const mockCallback = jest.fn();
11+
const { result } = renderHook(() =>
12+
useSimulateProgress(1000, mockCallback),
13+
);
14+
15+
// Initial progress should be 0
16+
expect(result.current).toBe(0);
17+
18+
// Fast-forward the timer, simulating time passing
19+
act(() => {
20+
jest.advanceTimersByTime(250);
21+
});
22+
23+
// Progress should update to 25%
24+
expect(result.current).toBe(25);
25+
26+
act(() => {
27+
jest.advanceTimersByTime(500); // Fast-forward another 500ms
28+
});
29+
30+
// Progress should update to 75%
31+
expect(result.current).toBe(75);
32+
33+
act(() => {
34+
jest.advanceTimersByTime(250); // Finish the remaining time
35+
});
36+
37+
// Progress should be 100%, and callback should be called
38+
expect(result.current).toBe(100);
39+
expect(mockCallback).toHaveBeenCalledTimes(1);
40+
});
41+
42+
it('should not call callback if progress is less than 100%', () => {
43+
const mockCallback = jest.fn();
44+
const { result } = renderHook(() =>
45+
useSimulateProgress(1000, mockCallback),
46+
);
47+
48+
// Fast-forward the timer to 50%
49+
act(() => {
50+
jest.advanceTimersByTime(500); // Fast-forward 500ms
51+
});
52+
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+
66+
// Fast-forward the timer halfway
67+
act(() => {
68+
jest.advanceTimersByTime(500);
69+
});
70+
71+
// Progress should be 50%
72+
expect(result.current).toBe(50);
73+
74+
// Unmount the component
75+
unmount();
76+
77+
// Clear the timer, ensuring no further updates
78+
act(() => {
79+
jest.advanceTimersByTime(500); // Finish the remaining time
80+
});
81+
82+
// Progress should not update further
83+
expect(result.current).toBe(50);
84+
85+
// Callback should not be called
86+
expect(mockCallback).not.toHaveBeenCalled();
87+
});
88+
});

docs/use-simulate-progress.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# useSimulateProgress
2+
3+
> A hook for simulate progress.
4+
5+
## Usage
6+
7+
```javascript
8+
import { useSimulateProgress } from '@mints/hooks';
9+
10+
const Example = () => {
11+
const progress = useSimulateProgress(duration, () => {
12+
console.log('Progress complete!');
13+
});
14+
15+
return (
16+
<div
17+
className="progress-bar"
18+
style={{ width: '100%', background: '#e0e0e0', height: '30px' }}
19+
>
20+
<div
21+
style={{
22+
width: `${progress}%`,
23+
background: 'green',
24+
color: '#fff',
25+
textAlign: 'center',
26+
height: '100%',
27+
}}
28+
>
29+
{progress}%
30+
</div>
31+
</div>
32+
);
33+
};
34+
```
35+
36+
## API
37+
38+
```typescript
39+
useSimulateProgress = (
40+
duration: number,
41+
onComplete: () => void,
42+
): number
43+
```

src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export * from './use-debounce';
33
export * from './use-localstorage';
44
export * from './use-outside-click';
55
export * from './use-request';
6+
export * from './use-simulate-progress';
67
export * from './use-toggle';

src/use-simulate-progress.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useState, useEffect } from 'react';
2+
3+
export const useSimulateProgress = (
4+
duration: number,
5+
onComplete: () => void,
6+
) => {
7+
const [progress, setProgress] = useState(0);
8+
9+
useEffect(() => {
10+
let progressValue = 0;
11+
const interval = setInterval(() => {
12+
progressValue += 5;
13+
setProgress(progressValue);
14+
15+
if (progressValue >= 100) {
16+
clearInterval(interval);
17+
onComplete();
18+
}
19+
}, duration / 20);
20+
21+
return () => clearInterval(interval);
22+
}, [duration, onComplete]);
23+
24+
return progress;
25+
};

0 commit comments

Comments
 (0)