Skip to content

[FIX] 버튼 "따닥"으로 인한 중복 호출로 시간표가 여러 개 생기는 문제 해결 #321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from

Conversation

useon
Copy link
Contributor

@useon useon commented Jul 18, 2025

🚩 연관 이슈

closed #258

📝 작업 내용

1️⃣ npm run dev 실행 안 되는 문제 해결

그동안 dev 실행이 안돼서 매번 build하고 preview로 확인했다고 하셔서 수정했습니다!

  • vite.config에서 port 3000으로 설정
  • dev 환경에서 undefined로 들어가는 url 수정

2️⃣ 버튼 "따닥"으로 인한 중복 호출 문제 해결

📌 문제 정의

간헐적으로 시간표 생성이나 수정 시 버튼을 여러 번 클릭하는 경우 여러 개 생성되는 문제가 발생했습니다.
image
참고로 제가 버튼 클릭이 느린지 생성이 하나만 돼서 커찬한테 부탁했더니 .., 이런 시간표를 생성했네요 ^^;;

해당 호출 당시 서버 로그
image

이렇게 짧은 시간에 요청이 두 번 가는 것을 확인할 수 있었습니다. 하나의 API 요청이 처리되기 전에 동일한 API 요청이 바로 들어와 두 개가 생성이 되는 것이 원인이었습니다.

✨ 해결 과정

두 가지 방법을 통해 UI 레벨에서 중복 클릭을 방지하고, 뮤테이션 로직 자체의 중복 실행을 방지하도록 구현했습니다.

1. useMutation의 isPending 상태를 활용한 버튼 클릭 disabled 처리

사용자가 뮤테이션이 진행 중일 때 버튼을 클릭하지 못하게 하여 중복 호출을 방지할 수 있습니다.
하지만 UI 레벨의 제어라서 개발자 도구에서 true로 변경하면 클릭할 수 있고, isPending 상태가 true로 변경되고 UI가 다시 렌더링되기까지 지연이 발생할 수 있습니다. 이때 버튼에 여러 번 클릭 이벤트가 발생할 수 있습니다.

2. usePreventDuplicateMutation

렌더링과 독립적으로 뮤테이션의 진행 여부를 추적하고자 useRef를 사용했습니다.
동작 원리는 다음과 같습니다.

  1. mutate 함수 호출 전 isMutatingRef.current = true로 뮤테이션이 시작됐음을 표시합니다.
  2. isMutatingRef.current = true 상태에서 mutate 함수가 다시 호출되면 새로운 호출을 차단하고 경고 메세지를 출력합니다.
  3. onSettled를 통해 뮤테이션ㄴ이 성공하든 실패하든 isMutatingRef.current = false로 재설정하여 중복 호출에 대한 락을 해제합니다.

또한 내부에서 useMutation을 실행하여 기존에 useMutate를 사용하는 사용처에서 별도의 코드 변경 없이 usePreventDuplicateMutation으로 감싸서 사용할 수 있습니다.

사용 예시

image

🏞️ 스크린샷 (선택)

아래는 버튼 클릭 시 mutation을 호출을 세 번 실행하도록 테스트한 결과입니다.
첫 번째 요청은 정상적으로 처리되어 API 호출이 되고, 두 번째 요청과 세 번째 요청은 바로 막히고 console이 찍히는 것을 확인할 수 있습니다.

default.mp4

🗣️ 리뷰 요구사항 (선택)

ㅎㅎㅎ 디베이트 합류 후 첫 PR이네요 두근 두근 !!!!!!!!!!!!!!! 잘 부탁드립니다 🫡✨

Summary by CodeRabbit

  • New Features

    • 중복된 요청을 방지하는 커스텀 훅이 추가되어, 테이블 추가 및 수정 시 중복 제출을 차단합니다.
    • 테이블 작성 단계에서 제출 중 상태를 나타내는 로딩 플래그가 추가되어 버튼이 중복 클릭되는 것을 방지합니다.
  • Refactor

    • 테이블 작성 관련 함수 및 상태 변수의 명명 규칙이 일관되게 변경되었습니다.
  • Chores

    • 개발 서버의 기본 포트가 3000번으로 명시적으로 설정되었습니다.
    • API 기본 URL 환경 변수 적용 방식이 단순화되었습니다.

@useon useon linked an issue Jul 18, 2025 that may be closed by this pull request
Copy link

coderabbitai bot commented Jul 18, 2025

Walkthrough

API 중복 요청(따닥 문제) 방지를 위해, 테이블 생성 및 수정 관련 mutation에 대해 중복 호출을 차단하는 커스텀 훅(usePreventDuplicateMutation)이 도입되었습니다. 관련 mutation 훅들이 이 커스텀 훅을 사용하도록 교체되었고, 로딩 상태 플래그 및 UI 반영을 위한 prop/상태 관리가 추가되었습니다. 그 외 axios 설정 및 Vite 포트 설정이 간단히 변경되었습니다.

Changes

파일/경로 요약 변경 내용 요약
src/hooks/mutations/usePreventDuplicateMutation.ts 중복 mutation 방지용 커스텀 훅 usePreventDuplicateMutation 신설
src/hooks/mutations/useAddDebateTable.ts
src/hooks/mutations/usePutDebateTable.ts
기존 useMutation 사용을 usePreventDuplicateMutation으로 교체
src/page/TableComposition/hook/useTableFrom.tsx mutation 로딩 상태 플래그(isAddingTable, isModifyingTable) 도입 및 반환, 함수명 camelCase로 변경
src/page/TableComposition/TableComposition.tsx 훅 반환값 및 함수명 변경 반영, isSubmitting prop 추가 및 전달
src/page/TableComposition/components/TimeBoxStep/TimeBoxStep.tsx isSubmitting prop 추가, 버튼 disabled 조건에 반영
src/apis/axiosInstance.ts baseURL 설정 로직 단순화
vite.config.ts dev server 포트 3000으로 명시적 지정

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI
    participant usePreventDuplicateMutation
    participant API

    User->>UI: 버튼 클릭 (테이블 생성/수정)
    UI->>usePreventDuplicateMutation: mutate() 호출
    alt 이미 mutation 진행 중
        usePreventDuplicateMutation-->>UI: 중복 호출 무시, 경고 로그
    else mutation 진행 중 아님
        usePreventDuplicateMutation->>API: API 요청 전송
        API-->>usePreventDuplicateMutation: 응답 반환
        usePreventDuplicateMutation-->>UI: onSuccess/onError/onSettled 콜백 실행
    end
Loading

Suggested labels

fix

Suggested reviewers

  • jaeml06
  • eunwoo-levi
  • katie424

Poem

🐇
중복 요청 따닥따닥,
이제는 걱정 끝!
한 번만 눌러도
토끼도 안심해요.
테이블 생성, 수정도
깔끔하게 한 번에!
코드 속 평화 찾아왔네.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-07-18T10_08_05_003Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@jaeml06 jaeml06 added the fix 버그 수정 label Jul 18, 2025
@jaeml06 jaeml06 requested review from jaeml06 and i-meant-to-be July 18, 2025 10:06
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
vite.config.ts (1)

18-20: 포트 번호 하드코딩 대신 환경변수 사용 권장

개발 환경마다 이미 3000 포트를 점유하고 있을 수 있어 충돌 위험이 있습니다. loadEnv로 환경변수를 불러오고 있으니, 동일한 방식으로 포트도 주입하면 유연성이 높아집니다.

-      port: 3000,
+      // 기본값 3000, 필요 시 VITE_DEV_SERVER_PORT 환경변수로 오버라이드
+      port: Number(env.VITE_DEV_SERVER_PORT) || 3000,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f77cc18 and b3a8488.

📒 Files selected for processing (8)
  • src/apis/axiosInstance.ts (1 hunks)
  • src/hooks/mutations/useAddDebateTable.ts (1 hunks)
  • src/hooks/mutations/usePreventDuplicateMutation.ts (1 hunks)
  • src/hooks/mutations/usePutDebateTable.ts (1 hunks)
  • src/page/TableComposition/TableComposition.tsx (3 hunks)
  • src/page/TableComposition/components/TimeBoxStep/TimeBoxStep.tsx (3 hunks)
  • src/page/TableComposition/hook/useTableFrom.tsx (2 hunks)
  • vite.config.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/hooks/mutations/useAddDebateTable.ts (1)
src/hooks/mutations/usePreventDuplicateMutation.ts (1)
  • usePreventDuplicateMutation (8-47)
src/page/TableComposition/TableComposition.tsx (1)
src/repositories/ApiDebateTableRepository.ts (2)
  • editTable (26-31)
  • addTable (21-24)
src/hooks/mutations/usePutDebateTable.ts (3)
src/type/type.ts (1)
  • DebateTableData (49-52)
src/hooks/mutations/usePreventDuplicateMutation.ts (1)
  • usePreventDuplicateMutation (8-47)
src/apis/responses/debateTable.ts (1)
  • PutDebateTableResponseType (9-11)
🔇 Additional comments (21)
src/apis/axiosInstance.ts (1)

10-10: 개발 환경 문제 해결을 위한 좋은 변경사항입니다.

baseURL 설정을 단순화하여 개발 환경에서 undefined URL 문제를 해결하는 좋은 접근법입니다. 이제 모든 환경에서 일관되게 환경 변수를 사용하게 됩니다.

src/hooks/mutations/useAddDebateTable.ts (2)

4-4: 중복 호출 방지를 위한 적절한 import입니다.

새로운 usePreventDuplicateMutation 훅을 import하여 버튼 따닥 문제를 해결하는 좋은 접근법입니다.


7-15: LGTM! 중복 mutation 방지 로직이 잘 적용되었습니다.

useMutationusePreventDuplicateMutation으로 교체하여 중복 API 호출을 방지하는 핵심 기능이 잘 구현되었습니다. 기존 인터페이스를 유지하면서 중복 방지 기능을 추가한 것이 좋습니다.

src/hooks/mutations/usePutDebateTable.ts (2)

4-4: 중복 호출 방지를 위한 적절한 import입니다.

usePreventDuplicateMutation 훅을 import하여 테이블 수정 시에도 중복 호출을 방지할 수 있도록 했습니다.


11-26: LGTM! 타입 안전성과 중복 방지 기능이 잘 구현되었습니다.

usePreventDuplicateMutation으로 교체하면서 제네릭 타입 매개변수를 올바르게 유지했고, 기존 mutation 로직과 콜백을 그대로 보존했습니다. 중복 호출 방지 기능이 깔끔하게 적용되었습니다.

src/page/TableComposition/TableComposition.tsx (3)

42-50: LGTM! 로딩 상태 관리와 함수명 개선이 잘 적용되었습니다.

useTableFrom 훅에서 새로운 로딩 상태 플래그(isAddingTable, isModifyingTable)를 추가하고 함수명을 camelCase로 통일한 것이 좋습니다. 이를 통해 UI 레벨에서 중복 호출을 방지할 수 있습니다.


62-65: 함수 호출이 새로운 네이밍에 맞게 잘 업데이트되었습니다.

AddTableEditTable에서 addTableeditTable로 일관된 camelCase 네이밍을 사용하도록 변경한 것이 좋습니다.


87-87: UI 레벨 중복 방지를 위한 적절한 prop 전달입니다.

현재 모드에 따라 적절한 로딩 상태를 isSubmitting prop으로 전달하여 버튼 비활성화 기능을 구현한 것이 좋습니다. 이는 PR의 핵심 목표인 "따닥" 문제 해결에 기여합니다.

src/page/TableComposition/components/TimeBoxStep/TimeBoxStep.tsx (3)

18-18: UI 상태 관리를 위한 적절한 prop 추가입니다.

isSubmitting prop을 추가하여 제출 상태에 따른 버튼 비활성화 기능을 구현할 수 있도록 했습니다.


28-28: 기본값 설정으로 하위 호환성을 보장한 좋은 구현입니다.

isSubmitting의 기본값을 false로 설정하여 기존 코드와의 호환성을 유지하면서 새로운 기능을 추가했습니다.


129-129: LGTM! 버튼 비활성화 로직이 완벽하게 구현되었습니다.

기존 조건(!isAbledSummitButton)과 새로운 제출 상태 조건(isSubmitting)을 모두 고려하여 버튼을 비활성화하는 로직이 잘 구현되었습니다. 이는 PR의 핵심 목표인 중복 호출 방지의 UI 레벨 구현을 완성합니다.

src/hooks/mutations/usePreventDuplicateMutation.ts (5)

1-6: import 구문이 올바르게 구성되어 있습니다.

필요한 React 훅들과 react-query의 타입들이 적절히 import되어 있습니다.


8-15: 제네릭 타입 정의가 잘 구성되어 있습니다.

useMutation과 동일한 제네릭 타입 매개변수를 사용하여 타입 안정성을 보장하고 있습니다.


16-26: 플래그 초기화 및 onSettled 콜백 구현이 적절합니다.

useRef를 사용하여 렌더링에 의존하지 않는 상태 관리를 하고 있으며, 기존 onSettled 콜백을 보존하면서 플래그를 재설정하는 로직이 올바릅니다.


30-44: 중복 호출 방지 로직이 잘 구현되어 있습니다.

useCallback을 사용하여 함수 참조를 안정화하고, 플래그를 통해 중복 호출을 효과적으로 차단하고 있습니다. 콘솔 경고 메시지도 적절합니다.


46-46: mutation 결과 반환이 올바르게 구현되어 있습니다.

기존 mutation의 모든 속성을 spread하면서 mutate 함수만 중복 방지 버전으로 오버라이드하는 방식이 적절합니다.

src/page/TableComposition/hook/useTableFrom.tsx (5)

83-88: mutation 훅 사용법이 올바르게 업데이트되었습니다.

isPending 상태를 isAddingTable로 추출하고, 콜백 함수를 명시적으로 첫 번째 인자로 전달하는 방식이 적절합니다.


90-98: 수정 mutation 훅 사용법이 적절합니다.

게스트 플로우를 고려한 네비게이션 로직이 보존되어 있으며, isPending 상태를 isModifyingTable로 추출하는 것이 적절합니다.


100-105: 함수명 변경이 일관성을 개선했습니다.

AddTable에서 addTable로 변경하여 camelCase 명명 규칙을 따르도록 개선되었습니다.


107-113: 수정 함수명도 일관성 있게 변경되었습니다.

EditTable에서 editTable로 변경하여 명명 규칙의 일관성을 유지하고 있습니다.


119-122: 로딩 상태 노출이 UI 반응성을 향상시킵니다.

isAddingTableisModifyingTable 상태를 반환하여 상위 컴포넌트에서 로딩 상태를 처리할 수 있도록 하는 것이 좋은 개선입니다.

Copy link
Contributor

@i-meant-to-be i-meant-to-be left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했습니다! 변경 사항이 간결하고 핵심에만 집중해주셔서 보기가 편했어요. 반드시 개선이 필요하다 싶은 사항은 없어서 승인을 남깁니다. 고생하셨어요!

mutateOptions?: Parameters<typeof mutation.mutate>[1],
) => {
if (isMutatingRef.current) {
console.warn('이미 요청이 처리 중 입니다.');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

대안: 콘솔에 알리지 말고 경고 창 띄우기

콘솔은 보통 개발자 아니면 보지 않을 것 같아서, 콘솔보다는 alert() 함수 등으로 간단하게나마 사용자에게 중복 요청임을 알리는 게 좋을 것 같아요.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

대안: 주석 추가

코드는 간결하나 - 특히나 제가 TanStack Query에 대한 배경 지식이 적기도 하고 - 주석이 없어서 어떤 과정을 거쳐 동작하는지 직관적으로 파악하기가 어려웠습니다. 앞으로 PR 작성하시면서 여유가 조금 있으시다면... 핵심 코드에 간단한 주석 한 줄 정도만 달아주세요! 흐름을 이해하고 썬데이가 코드를 작성한 의도를 파악하는 게 훨씬 수월할 것 같습니다.

@i-meant-to-be
Copy link
Contributor

추가로 하나 더 적자면, src/main.tsx의 코드 10~17번 줄까지 지워야 npm run dev가 제대로 동작하는 것 같아요. 이 코드가 엑세스 토큰을 모방 토큰으로 덮어씌우고 있어서 Google 로그인이 유지되지 않네요.

Copy link
Contributor

@jaeml06 jaeml06 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구현하느라 고생하셨습니다. useMutate를 래핑하는 방식에서 좋은 인사이트를 얻을 수 있었습니다. 덕분에 useMutate에 대해서 조금 더 잘알게 되는 계기가 아니었을까 싶습니다. 이번에 타입을 비교하면서 실제 구현해주신 부분과 차이가 있어서 궁금증으로 코멘트를 남깁니다. 한번확인해주세요!


export function usePreventDuplicateMutation<
TData = unknown,
TError = Error,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실제 useMutation함수에서 Error가 아니라 DefaultError를 기본 타입으로 사용하고 있는데 Error타입을 선언하신 이유가 있을까요?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fix 버그 수정
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

[FIX] API 중복 요청 방지(따닥 문제)
3 participants