Skip to content

Conversation

@gudusol
Copy link
Contributor

@gudusol gudusol commented Mar 29, 2025

📌 Related Issue Number


Checklist

  • 🎋 base 브랜치를 제대로 설정했나요?
  • 🖌️ PR 제목은 형식에 맞게 잘 작성했나요?
  • 🏗️ 빌드는 성공했나요? (pnpm build)
  • 🧹 불필요한 코드는 제거했나요? e.g. console.log
  • 🙇‍♂️ 리뷰어를 지정했나요?
  • 🏷️ 라벨은 등록했나요?

✅ Key Changes

이번 PR에서 작업한 내용을 간략히 설명해주세요

문제상황

image

tanstack query의 refetchOnWindowFocus 때문에 다른 창에 갔당오면 데이터를 refetch 하면서 저장하지 않는 입력값들이 초기화 돼버리는 문제가 생김

해결방법

  1. refetchOnWindowFocus 설정과 적절한 staleTime 설정
  • 가장 일반적인 방법
  1. defaultOptions로 staleTime, gcTime을 Infinity로 설정하고, 적절히 Invalidate
  • 내가 선택한 방법

이렇게 한 이유는 다음과 같음.

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: Infinity,
      gcTime: Infinity,
    },
  },
});

이렇게 해서 모든 쿼리를 조건없이 캐싱 해버림

이유는, 관리자 페이지에서는 주기적으로 갱신돼야 하는 데이터가 없음.
문제 -> 문제가 모인 세트 -> 세트가 날짜에 연결된 발행 데이터들만 있는데, 이는 관리자페이지에서 어떤 수정이 일어나지 않는한 변경되지 않음.

그래서 모든 데이터를 Infinity로 캐싱하고, 수정이 일어날때 적절하게 invalidate시켜주는 방법을 선택했음

tanstack query는 stale인 데이터가 트리거(OnWindowFocus 등)를 만족하면 refetch가 일어남
즉, 이렇게 모든 데이터를 fresh하게 유지하게되면 현재 문제 상황인 데이터 refetch 문제도 해결가능함
(fresh라서 onWindowFocus나 reconnect 등이 일어나도 refech가 안됨)

대신, 업데이트 되어야하는 모든 쿼리를 적절하게 invalidate 시켜주지 않으면 최신 데이터가 제대로 보이지 않을 수있음.


데이터 Invalidate 시키기

업데이트가 크게 문제, 세트, 발행 세군데에서 일어남.
문제 -> 문제가 모인 세트 -> 세트가 날짜에 연결된 발행 구조이기 때문에 사실 문제가 수정되면 모든 데이터가 바뀐다고 할 수 있음

그래서 문제의 업데이트에 대해서는 그냥 모든 쿼리를 invalidate 시켜버림
(조금 비효율적일 수는 있지만, 뭘 빠뜨리는것보다는 낫다고 판단함,,,)

세트의 업데이트에 대한 invalidate

  • 해당 id 세트
  • 세트 목록
  • 컨펌된 세트 목록

발행 업데이트에 대한 invalidate

  • 해당 연월에 대한 발행 목록

useInvalidate 훅 생성

반복되는 invalidate 를 커스텀 훅으로 빼줬음.
필요한 query를 정확하게 Invalidate 시키기 위함도 있고,
openapi-react-query를 쓰다보니 invalidate 코드가 너무길어서 반복을 줄이기 위함도 있음

모든 쿼리 invalidate

  const invalidateAll = () => {
    queryClient.invalidateQueries();
  };

문항 세트 관련 쿼리 invalidate

  const invalidateProblemSet = (problemSetId: number) => {
    return Promise.all([
      queryClient.invalidateQueries({
        queryKey: $api.queryOptions('get', '/api/v1/problemSet/{problemSetId}', {
          params: {
            path: {
              problemSetId,
            },
          },
        }).queryKey,
      }),
      queryClient.invalidateQueries({
        queryKey: $api.queryOptions('get', '/api/v1/problemSet/search').queryKey,
      }),
      queryClient.invalidateQueries({
        queryKey: $api.queryOptions('get', '/api/v1/problemSet/confirm/search').queryKey,
      }),
    ]);
  };

문항 발행 관련 쿼리 invalidate

 const invalidatePublish = (year: number, month: number) => {
    queryClient.invalidateQueries({
      queryKey: $api.queryOptions('get', '/api/v1/publish/{year}/{month}', {
        params: {
          path: {
            year,
            month,
          },
        },
      }).queryKey,
    });
  };

💡 New Insights & Learnings

  const invalidateProblemSet = (problemSetId: number) => {
    queryClient.invalidateQueries({
      queryKey: [
        $api.queryOptions('get', '/api/v1/problemSet/{problemSetId}', {
          params: {
            path: {
              problemSetId,
            },
          },
        }).queryKey,
        $api.queryOptions('get', '/api/v1/problemSet/search').queryKey,
        $api.queryOptions('get', '/api/v1/problemSet/confirm/search').queryKey,
      ],
    });
  };

원래 문제 세트 invalidate할때 이런식으로 여러개의 쿼리를 invalidate시키려고 했는데, 제대로안됨

알아보니, 저렇게 여러개의 쿼리를 넣으면 or 조건으로 처리되는게 아니라,

  • [queryKey1, queryKey2, queryKey3]로 시작하는 모든 쿼리와 일치.
  • queryKey1로 시작하는 쿼리와 queryKey2로 시작하는 쿼리를 모두 무효화하는 것이 아님
    라고함.

그래서 각각에 대해 invalidate를 시키려면
Promise.all을 이용해서 모두를 invalidate시켜야함

따라서

  const invalidateProblemSet = (problemSetId: number) => {
    return Promise.all([
      queryClient.invalidateQueries({
        queryKey: $api.queryOptions('get', '/api/v1/problemSet/{problemSetId}', {
          params: { path: { problemSetId } },
        }).queryKey,
      }),
      queryClient.invalidateQueries({
        queryKey: $api.queryOptions('get', '/api/v1/problemSet/search').queryKey,
      }),
      queryClient.invalidateQueries({
        queryKey: $api.queryOptions('get', '/api/v1/problemSet/confirm/search').queryKey,
      }),
    ]);
  };

요런 코드가 됐음.

잘 동작함 👍

@gudusol gudusol added 🐞 Fix 버그 수정 🐽 태승 labels Mar 29, 2025
@gudusol gudusol self-assigned this Mar 29, 2025
@gudusol gudusol merged commit 4d821d4 into main Mar 29, 2025
1 check passed
@gudusol gudusol deleted the fix/admin/query-option-#52 branch March 29, 2025 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[fix] Admin 페이지 입력데이터 사라지는 문제

2 participants