-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
263 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ lib | |
node_modules | ||
.history | ||
.idea | ||
.vscode | ||
coverage | ||
.doc | ||
.DS_Store | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { renderHook, act } from '@testing-library/react-hooks'; | ||
import { useRef } from 'react'; | ||
import useLockFn from '../index'; | ||
import { sleep } from '../../utils/testingHelpers'; | ||
|
||
describe('useLockFn', () => { | ||
it('should be defined', () => { | ||
expect(useLockFn).toBeDefined(); | ||
}); | ||
|
||
const setUp = (): any => | ||
renderHook(() => { | ||
const countRef = useRef(0); | ||
const locked = useLockFn(async (step: number) => { | ||
countRef.current += step; | ||
await sleep(50); | ||
}); | ||
|
||
return { | ||
locked, | ||
countRef, | ||
}; | ||
}); | ||
|
||
it('should work', async () => { | ||
const hook = setUp(); | ||
const { locked, countRef } = hook.result.current; | ||
locked(1); | ||
expect(countRef.current).toBe(1); | ||
locked(2); | ||
expect(countRef.current).toBe(1); | ||
await sleep(30); | ||
locked(3); | ||
expect(countRef.current).toBe(1); | ||
await sleep(30); | ||
locked(4); | ||
expect(countRef.current).toBe(5); | ||
locked(5); | ||
expect(countRef.current).toBe(5); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/** | ||
* title: Prevent duplicated submits | ||
* desc: Before the `submit` function finishes, the other click actions will be ignored. | ||
* | ||
* title.zh-CN: 防止重复提交 | ||
* desc.zh-CN: 在 `submit` 函数执行完成前,其余的点击动作都会被忽略。 | ||
*/ | ||
|
||
import React, { useState } from 'react'; | ||
import { message } from 'antd'; | ||
import { useLockFn } from 'ahooks'; | ||
|
||
function mockApiRequest() { | ||
return new Promise((resolve) => { | ||
setTimeout(() => { | ||
resolve(); | ||
}, 2000); | ||
}); | ||
} | ||
|
||
export default () => { | ||
const [count, setCount] = useState(0); | ||
|
||
const submit = useLockFn(async () => { | ||
message.info('Start to submit'); | ||
await mockApiRequest(); | ||
setCount((val) => val + 1); | ||
message.success('Submit finished'); | ||
}); | ||
|
||
return ( | ||
<> | ||
<p>Submit count: {count}</p> | ||
<button onClick={submit}>Submit</button> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
--- | ||
title: useLockFn | ||
nav: | ||
title: Hooks | ||
path: /hooks | ||
group: | ||
title: Advanced | ||
path: /advanced | ||
--- | ||
|
||
# useLockFn | ||
|
||
Add lock to an async function to prevent parallel executions. | ||
|
||
## Examples | ||
|
||
### Prevent duplicated submits | ||
|
||
<code src="./demo/demo1.tsx" /> | ||
|
||
## API | ||
|
||
```typescript | ||
function useLockFn<P extends any[] = any[], V extends any = any>( | ||
fn: (...args: P) => Promise<V> | ||
): fn: (...args: P) => Promise<V | undefined> | ||
``` | ||
|
||
### Result | ||
|
||
| 参数 | 说明 | 类型 | | ||
|------|---------------------------|---------------------------| | ||
| fn | The async function with lock | `(...args: any[]) => any` | | ||
### Params | ||
| 参数 | 说明 | 类型 | 默认值 | | ||
|----------------|------------------|---------------------------|--------| | ||
| fn | An async function | `(...args: any[]) => any` | - | | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { useRef } from 'react'; | ||
|
||
function useLockFn<P extends any[] = any[], V extends any = any>(fn: (...args: P) => Promise<V>) { | ||
const lockRef = useRef(false); | ||
|
||
return async function (...args: P) { | ||
if (lockRef.current) return; | ||
lockRef.current = true; | ||
try { | ||
const ret = await fn(...args); | ||
lockRef.current = false; | ||
return ret; | ||
} catch (e) { | ||
lockRef.current = false; | ||
throw e; | ||
} | ||
}; | ||
} | ||
|
||
export default useLockFn; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
--- | ||
title: useLockFn | ||
nav: | ||
title: Hooks | ||
path: /hooks | ||
group: | ||
title: Advanced | ||
path: /advanced | ||
--- | ||
|
||
# useLockFn | ||
|
||
用于给一个异步函数增加竞态锁,防止并发执行。 | ||
|
||
## 代码演示 | ||
|
||
### 避免重复提交 | ||
|
||
<code src="./demo/demo1.tsx" /> | ||
|
||
## API | ||
|
||
```typescript | ||
function useLockFn<P extends any[] = any[], V extends any = any>( | ||
fn: (...args: P) => Promise<V> | ||
): fn: (...args: P) => Promise<V | undefined> | ||
``` | ||
|
||
### Result | ||
|
||
| 参数 | 说明 | 类型 | | ||
|------|---------------------------|---------------------------| | ||
| fn | 增加了竞态锁的函数 | `(...args: any[]) => any` | | ||
|
||
### Params | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
|----------------|------------------|---------------------------|--------| | ||
| fn | 需要增加竞态锁的函数 | `(...args: any[]) => any` | - | | ||
|