Skip to content

Commit

Permalink
docs(react): useBlockPromiseMultipleClick 문서 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
ssi02014 committed Apr 30, 2024
1 parent 941af5d commit 84b0ddc
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/great-parents-approve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/react': minor
---

feat(react): useBlockDoubleClick 추가 @Sangminnn
99 changes: 99 additions & 0 deletions docs/docs/react/hooks/useBlockPromiseMultipleClick.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useState } from 'react';
import { useBlockPromiseMultipleClick } from '@modern-kit/react';

# useBlockPromiseMultipleClick

인자로 넘겨준 Callback 함수의 `Promise` 동작을 수행하는 동안 `중복 호출이 불가능하도록 차단`하는 커스텀 훅입니다.

[useDebounce](https://modern-agile-team.github.io/modern-kit/docs/react/hooks/useDebounce)를 사용해 중복 호출을 방지할 수는 있지만, 시간 값에 의존하기 때문에 만약 `Promise`가 이행될 때까지 호출을 완벽하게 차단해야 한다면 부족합니다.

해당 훅은 Promise 동작을 수행하는 동안 중복 호출을 방지하기 때문에, `Promise` 이행을 보장하면서 중복 호출을 방지하고 싶을 때 사용할 수 있습니다.

<br />

## Interface
```tsx
const useBlockPromiseMultipleClick: () => {
isLoading: boolean;
blockMultipleClick: (callback: () => Promise<unknown>) => Promise<void>;
};
```

## Usage

```tsx
import React, { useState } from 'react';
import { useBlockPromiseMultipleClick } from '@modern-kit/react';

interface Value {
userId: number;
id: number;
title: string;
completed: boolean;
}

const Example = () => {
const [blockingCount, setBlockingCount] = useState(1);
const [nonBlockingCount, setNonBlockingCount] = useState(1);
const [value, setValue] = useState<Value | null>(null);

const { isLoading, blockMultipleClick } = useBlockPromiseMultipleClick();

const fetchApi = async () => {
const res = await fetch(
`https://jsonplaceholder.typicode.com/todos/${blockingCount}`
).then((response) => response.json());

setValue(res);
setBlockingCount(blockingCount + 1);
};

const handleClick = () => {
setNonBlockingCount(nonBlockingCount + 1);
blockMultipleClick(fetchApi); // (*) Promise 반환하는 함수를 인자로 넣어주세요.
};

return (
<div>
<button onClick={handleClick}>버튼 클릭</button>
<div>
<p>BlockingCount: {blockingCount}</p>
<p>NonBlockingCount: {nonBlockingCount}</p>
</div>
{isLoading ? <p>로딩중</p> : <p>{value?.title}</p>}
</div>
);
};
```

## Example

export const Example = () => {
const [blockingCount, setBlockingCount] = useState(1);
const [nonBlockingCount, setNonBlockingCount] = useState(1);
const [value, setValue] = useState(null);
const { isLoading, blockMultipleClick } = useBlockPromiseMultipleClick();
const fetchApi = async () => {
const res = await fetch(
`https://jsonplaceholder.typicode.com/todos/${blockingCount}`
).then((response) => response.json());
setValue(res);
setBlockingCount(blockingCount + 1);
};
const handleClick = () => {
setNonBlockingCount(nonBlockingCount + 1);
blockMultipleClick(fetchApi);
};
return (
<div>
<button onClick={handleClick}>버튼 클릭</button>
<div>
<p>BlockingCount: {blockingCount}</p>
<p>NonBlockingCount: {nonBlockingCount}</p>
</div>
{isLoading ? <p>로딩중</p> : <p>{value?.title}</p>}
</div>
);
};

<Example />
2 changes: 1 addition & 1 deletion packages/react/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './useAsyncPreservedCallback';
export * from './useAsyncProcessQueue';
export * from './useBlockPromiseMultipleClick';
export * from './useDebounce';
export * from './useForceUpdate';
export * from './useImageStatus';
Expand All @@ -20,4 +21,3 @@ export * from './useUnMount';
export * from './useVisibilityChange';
export * from './useWindowScrollTo';
export * from './useWindowSize';
export * from './useBlockPromiseMultipleClick';
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useRef, useState } from 'react';

export const useBlockMultipleClick = () => {
export const useBlockPromiseMultipleClick = () => {
const [isLoading, setIsLoading] = useState(false);
const isClicked = useRef(false);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest';
import { screen, renderHook } from '@testing-library/react';
import { renderSetup } from '../../utils/test/renderSetup';
import { useBlockMultipleClick } from '.';
import { useBlockPromiseMultipleClick } from '.';

const delay = (time: number) => {
return new Promise<void>((resolve) => {
Expand All @@ -17,10 +17,10 @@ afterEach(() => {
vi.useRealTimers();
});

describe('useBlockMultipleClick', () => {
it('should block double click', async () => {
describe('useBlockPromiseMultipleClick', () => {
it('should block multiple button clicks until the promise in the callback function is resolved', async () => {
const mockFn = vi.fn(async () => await delay(1000));
const { result } = renderHook(useBlockMultipleClick);
const { result } = renderHook(useBlockPromiseMultipleClick);

const { blockMultipleClick } = result.current;
expect(result.current.isLoading).toBe(false);
Expand All @@ -29,7 +29,7 @@ describe('useBlockMultipleClick', () => {

const { user } = renderSetup(
<button onClick={onClick}>TestButton</button>,
{ delay: null },
{ delay: null }
);

const button = screen.getByRole('button');
Expand Down

0 comments on commit 84b0ddc

Please sign in to comment.