Skip to content

반응 기능 낙관적 업데이트 및 캐시 관리 개선#954

Merged
klmhyeonwoo merged 1 commit into
developfrom
feature/942
Jul 24, 2026
Merged

반응 기능 낙관적 업데이트 및 캐시 관리 개선#954
klmhyeonwoo merged 1 commit into
developfrom
feature/942

Conversation

@klmhyeonwoo

@klmhyeonwoo klmhyeonwoo commented Jul 23, 2026

Copy link
Copy Markdown
Member

🏄🏼‍♂️‍ Summary (요약)

  • 반응 기능의 낙관적 UI 업데이트 로직을 전반적으로 개선했습니다.
  • useReplaceRetrospectReaction 훅을 제거하고, 반응 변경 로직을 최적화했습니다.
  • 반응 캐시 관리 함수를 분리하여 재사용성과 안정성을 높였습니다.

🫨 Describe your Change (변경사항)

  • useReplaceRetrospectReaction 훅을 제거하고, 반응 변경 시 기존 반응 삭제 후 새 반응을 추가하는 방식으로 로직을 변경했습니다.
  • 여러 낙관적 업데이트를 동시에 관리하기 위해 pendingCreateRefPromise에서 Map 형태로 변경했습니다.
  • 반응 캐시 업데이트를 위한 addRetrospectReactionCacheremoveRetrospectReactionCache 함수를 추가했습니다.
  • UI 컴포넌트에서 isMutatingdisabled 상태 관리를 제거하여 코드 복잡성을 줄였습니다.
  • 반응 개수가 1개 초과일 때만 개수를 표시하도록 UI를 개선했습니다.

🧐 Issue number and link (참고)

closes: #942

📚 Reference (참조)

한 사용자가 하나의 답변에 여러 종류의 반응을 남길 수 있도록 변경합니다.

반응 개수는 2개 이상일 때만 표시하고, 삭제 후 재등록 방식의 변경 mutation을 제거해 등록과 삭제 낙관적 업데이트 흐름을 단순화합니다.
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • Not Rabbit

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d3dd6335-068b-46ad-99a8-9b5c50b8e881

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/942

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

Comment @coderabbitai help to get the list of available commands.

@github-actions
github-actions Bot requested review from JaeIn1, prgmr99 and supersett July 23, 2026 15:26
@github-actions github-actions Bot changed the title feat(reaction): 여러 반응 추가 지원 반응 기능 낙관적 업데이트 및 캐시 관리 개선 Jul 23, 2026

return {
...mutation,
mutate: (params: PostRetrospectReactionParams, options?: Parameters<typeof mutation.mutate>[1]) =>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

muate랑 mutateAsync를 정의해서 내보내는 이유는 컴포넌트 단에서 낙관적 업데이트를 처리하지 않아도 되고, 나중에 다른 곳에서 사용하더라도 해당 파일 안에 로직으로 처리되어있는 낙관적 업데이트를 자동으로 처리될 수 있어 이렇게 처리했습니다!

@prgmr99 prgmr99 Jul 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

형님! 질문이 있습니다!
mutation.mutate과 mutate(별도 정의)를 구분해서 mutate(별도 정의)를 사용하면 낙관적 업데이트를 따로 구현하지 않고 적용할 수 있다는 의미로 이해했어요!

처음에는 mutate과 mutation.mutate을 사용할 때 외부에서 봤을 때는 사실 차이가 없다고 생각하고 사용할 수도 있고, 내부(usePostRetrospectReaction.ts)으로 들어오지 않는 이상 둘이 차이가 있다는 사실을 인지하기 어렵다고 생각했어요!

그래서 낙관적 업데이트가 적용된 mutate만 존재해도 되지 않을까? mutation.mutate은 낙관적 업데이트가 적용되지 않는 mutate인데, 이것을 사용할 일이 있을까 싶은 생각이 들었어요..!! (이것이 질문입니다!)

그래서 applyOptimisticPost를 정의해주셨는데, onMutate에서 활용하면 낙관적 업데이트가 적용된 mutate 하나만 존재하는 형태로 사용할 수 있을 것 같아요!

export const usePostRetrospectReaction = () => {
    const queryClient = useQueryClient();

    return useMutation({
      mutationFn: async ({ spaceId, retrospectId, answerId, emojiCode }: PostRetrospectReactionParams) => {
        await api.post(`/space/${spaceId}/retrospect/${retrospectId}/reaction`, { answerId, emojiCode });
      },
      onMutate: ({ spaceId, retrospectId, answerId, emojiCode, member }) =>
        addRetrospectReactionCache(
          queryClient,
          { spaceId, retrospectId },
          { answerId, reaction: createOptimisticReaction(emojiCode, member) },
        ),
      onError: (_, { spaceId, retrospectId }, context) => {
        rollbackRetrospectReactionCache(queryClient, { spaceId, retrospectId }, context?.previousReactions);
      },
      onSettled: (_, __, { spaceId, retrospectId }) => {
        void invalidateRetrospectReactionCache(queryClient, { spaceId, retrospectId });
      },
    });
  };

형님의 의도와 다를 수도 있어서 참고만 해주셔도 됩니다!!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

구두로 같이 이야기한 것처럼 mutate에 이름이 겹칠 것 같아, 낙관적 업데이트가 적용되지 않은 mutate 기본 동작은 살리면서 optimisticMutate 라는 별칭으로 새롭게 리턴하는 형식으로 수정을 진행해보겠습니다!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

관련 이슈 : #955

@prgmr99 prgmr99 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

고생하셨습니다~!!!


return {
...mutation,
mutate: (params: PostRetrospectReactionParams, options?: Parameters<typeof mutation.mutate>[1]) =>

@prgmr99 prgmr99 Jul 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

형님! 질문이 있습니다!
mutation.mutate과 mutate(별도 정의)를 구분해서 mutate(별도 정의)를 사용하면 낙관적 업데이트를 따로 구현하지 않고 적용할 수 있다는 의미로 이해했어요!

처음에는 mutate과 mutation.mutate을 사용할 때 외부에서 봤을 때는 사실 차이가 없다고 생각하고 사용할 수도 있고, 내부(usePostRetrospectReaction.ts)으로 들어오지 않는 이상 둘이 차이가 있다는 사실을 인지하기 어렵다고 생각했어요!

그래서 낙관적 업데이트가 적용된 mutate만 존재해도 되지 않을까? mutation.mutate은 낙관적 업데이트가 적용되지 않는 mutate인데, 이것을 사용할 일이 있을까 싶은 생각이 들었어요..!! (이것이 질문입니다!)

그래서 applyOptimisticPost를 정의해주셨는데, onMutate에서 활용하면 낙관적 업데이트가 적용된 mutate 하나만 존재하는 형태로 사용할 수 있을 것 같아요!

export const usePostRetrospectReaction = () => {
    const queryClient = useQueryClient();

    return useMutation({
      mutationFn: async ({ spaceId, retrospectId, answerId, emojiCode }: PostRetrospectReactionParams) => {
        await api.post(`/space/${spaceId}/retrospect/${retrospectId}/reaction`, { answerId, emojiCode });
      },
      onMutate: ({ spaceId, retrospectId, answerId, emojiCode, member }) =>
        addRetrospectReactionCache(
          queryClient,
          { spaceId, retrospectId },
          { answerId, reaction: createOptimisticReaction(emojiCode, member) },
        ),
      onError: (_, { spaceId, retrospectId }, context) => {
        rollbackRetrospectReactionCache(queryClient, { spaceId, retrospectId }, context?.previousReactions);
      },
      onSettled: (_, __, { spaceId, retrospectId }) => {
        void invalidateRetrospectReactionCache(queryClient, { spaceId, retrospectId });
      },
    });
  };

형님의 의도와 다를 수도 있어서 참고만 해주셔도 됩니다!!

@klmhyeonwoo
klmhyeonwoo merged commit 04e28db into develop Jul 24, 2026
4 checks passed
@klmhyeonwoo
klmhyeonwoo deleted the feature/942 branch July 24, 2026 03:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants