2026.07.21

핵심 문제: 책임의 위치가 잘못됐다


기존 패턴

부모(index.tsx)
  └─ const { data, refetch } = useQuery(...)
  └─ <TableSection refetch={refetch} />

TableSection
  └─ <Dialog refetch={refetch} />

Dialog
  └─ mutation 성공 → refetch() 호출

왜 문제인가

1. 책임 분리 위반

mutation이 성공했을 때 "캐시를 갱신한다"는 건 mutation의 side effect다. 근데 그 책임을 컴포넌트가 들고 있었다. mutation hook 안에서 처리해야 할 일을 밖으로 꺼낸 것.

2. prop drilling

refetch가 index → TableSection → Dialog 3단계를 거쳐 전달됨. 중간 컴포넌트는 쓰지도 않으면서 받아서 넘기기만 함.

3. 단일 인스턴스만 갱신

refetch()는 그 컴포넌트에서 쓰고 있는 query 인스턴스 하나만 갱신한다. 만약 같은 queryKey를 다른 페이지나 컴포넌트에서도 쓰고 있으면 그쪽은 갱신이 안 된다.

4. 컴포넌트 간 결합도 증가

Dialog가 "누가 나를 렌더링했는지"를 알아야 했다. refetch가 어디서 오는지 알아야 하니까. 재사용이 어려워짐.


수정 후 패턴

mutation hook
  └─ onSuccess: () => {
       queryClient.invalidateQueries({ queryKey: [...] })
     }

mutation hook을 어디서 호출하든 자동으로 캐시 무효화. 컴포넌트는 refetch를 알 필요가 없다.