Skip to content

fix: handwriting API 캐시 전략 개선#288

Open
b0nsu wants to merge 2 commits intodevelopfrom
fix/mat-349-handwriting-api-cache-strategy
Open

fix: handwriting API 캐시 전략 개선#288
b0nsu wants to merge 2 commits intodevelopfrom
fix/mat-349-handwriting-api-cache-strategy

Conversation

@b0nsu
Copy link
Copy Markdown
Collaborator

@b0nsu b0nsu commented Apr 24, 2026

Summary

handwriting API의 캐시 전략을 개선하여 불필요한 refetch를 방지하고 저장 후 즉시 캐시를 반영합니다.

Linear

Changes

  • putUpdateHandwriting: 주석 처리된 invalidateQueriessetQueryData로 변경하여 저장 후 서버 재요청 없이 캐시 즉시 반영
  • useGetHandwriting: staleTime: Infinity, refetchOnWindowFocus: false 추가하여 탭 전환/포커스 시 불필요한 refetch 방지

Testing

  • 스크랩 필기 저장 후 캐시 즉시 반영 확인
  • 탭 전환 시 refetch로 인한 깜빡임 없음 확인

Risk / Impact

  • 영향 범위: 스크랩 handwriting 조회/저장 API hook
  • 기존 동작에 영향 없음 (캐시 전략만 변경)

- putUpdateHandwriting: invalidateQueries → setQueryData로 변경하여 저장 후 즉시 캐시 반영
- useGetHandwriting: staleTime: Infinity, refetchOnWindowFocus: false 추가하여 불필요한 refetch 방지

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@linear
Copy link
Copy Markdown

linear Bot commented Apr 24, 2026

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pointer-admin Ready Ready Preview, Comment May 2, 2026 7:52am

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts the React Query caching strategy for the student scrap handwriting API in apps/native, aiming to prevent unnecessary refetches and to reflect saved handwriting immediately in the local cache.

Changes:

  • useGetHandwriting: sets staleTime: Infinity and refetchOnWindowFocus: false to reduce refetches on focus/tab switches.
  • useUpdateHandwriting: replaces a (previously commented) invalidation approach with setQueryData to update the handwriting query cache immediately after saving.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
apps/native/src/apis/controller/student/scrap/handwriting/useGetHandwriting.ts Tweaks query freshness/refetch behavior to avoid UI flicker due to refetching.
apps/native/src/apis/controller/student/scrap/handwriting/putUpdateHandwriting.ts Updates cache on mutation success so UI can reflect saved handwriting without refetch.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +32 to +37
onSuccess: (_, { scrapId, request }) => {
queryClient.setQueryData(
TanstackQueryClient.queryOptions('get', '/api/student/scrap/{scrapId}/handwriting', {
params: { path: { scrapId } },
}).queryKey,
{ data: request.data }
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

setQueryData{ data: request.data }를 넣으면 GET /handwriting 캐시 타입(스크랩 ID/updatedAt 포함 ScrapHandwritingResp)과 shape가 달라지고, 서버가 응답에서 보정한 값/updatedAt도 반영되지 않습니다. onSuccess의 첫 번째 인자인 mutation response를 사용해 캐시를 동일한 응답 객체로 설정하거나, 기존 캐시와 merge해서 scrapId/updatedAt 필드를 유지하도록 수정해 주세요.

Suggested change
onSuccess: (_, { scrapId, request }) => {
queryClient.setQueryData(
TanstackQueryClient.queryOptions('get', '/api/student/scrap/{scrapId}/handwriting', {
params: { path: { scrapId } },
}).queryKey,
{ data: request.data }
onSuccess: (response, { scrapId }) => {
queryClient.setQueryData(
TanstackQueryClient.queryOptions('get', '/api/student/scrap/{scrapId}/handwriting', {
params: { path: { scrapId } },
}).queryKey,
response

Copilot uses AI. Check for mistakes.
},
{
enabled,
staleTime: Infinity,
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

staleTime: Infinity로 인해 이 쿼리는 기본적으로 더 이상 stale 상태가 되지 않아, 이후 데이터 변경은 mutation에서 setQueryData/invalidateQueries로 보장해야 합니다. 현재 useDeleteHandwriting['scrap','handwriting',scrapId] 형태의 queryKey를 invalidate하고 있어(openapi-react-query TanstackQueryClient.useQuery의 queryKey와 불일치), 삭제 후에도 이 캐시가 남을 수 있습니다. handwriting 관련 mutation들이 모두 TanstackQueryClient.queryOptions(...).queryKey를 사용하도록 정리하거나, 삭제 시 해당 queryKey에 대해 setQueryData(undefined)/invalidate를 해 주세요.

Suggested change
staleTime: Infinity,

Copilot uses AI. Check for mistakes.
@b0nsu
Copy link
Copy Markdown
Collaborator Author

b0nsu commented May 1, 2026

Stacked PR 실기기 테스트에서 확인됨

MAT-355 (PR #299) 실기기 테스트 중 이 PR이 해결하는 이슈가 재현되었습니다:

  • 스크랩 진입 → 필기 40획 정상 로딩 → TanStack Query refetch → 빈 데이터(36 bytes)로 덮어씌움 → 필기 사라짐
  • 이 PR의 staleTime: Infinity + refetchOnWindowFocus: false 적용으로 해결됨

이 PR 머지 후 stacked PR (#298~#307) 테스트 시 해당 이슈 해소 예상.

@b0nsu
Copy link
Copy Markdown
Collaborator Author

b0nsu commented May 1, 2026

🔍 canvas ref 타이밍 이슈 발견 → PR #308에서 수정 완료

이 PR의 캐시 전략 변경(staleTime: Infinity + setQueryData)은 정상 동작하나, 디버깅 중 기존 useHandwritingManager의 canvas ref 타이밍 문제가 확인되었습니다.

증상

스크랩 재진입 시 필기 데이터가 유실됨.

원인 (수정됨)

canvasRef 불변으로 effect 재실행 안 됨 → canvas ref 타이밍도 문제였지만, 근본 원인은 effect 실행 순서:

  1. useHandwritingManager 로드 effect → strokes 정상 적용
  2. ScrapDetailScreen scrapId effect → canvasRef.current?.clear() → 캔버스 비움
  3. clear()로 인한 hasUnsavedChanges: true 오탐 → autosave → 빈 캔버스 서버 저장

staleTime: Infinity 이전에는 데이터가 네트워크 응답 후 도착하여 clear → 로드 순서였지만, 캐시 즉시 반환으로 로드 → clear 순서가 역전됨.

해소

MAT-524 PR #308에서 수정 완료:

  • canvas clear 책임을 ScrapDetailScreenuseHandwritingManager로 이동 (로드 직전 clear)
  • initialLoadDoneRef로 로드 완료 전 autosave 차단
  • 데이터 없는 스크랩 처리 추가

Phase 3 (MAT-365)에서 상태머신 기반 재작성 시 구조적 해소 예정.

- putUpdateHandwriting: { data: request.data } → response (서버 응답 전체 사용)
- deleteHandwriting: 하드코딩 queryKey → TanstackQueryClient.queryOptions() 사용

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@sterdsterd sterdsterd left a comment

Choose a reason for hiding this comment

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

merge는 #308 이랑 같이 하면 될듯용

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.

3 participants