🔥 뮤테이션 응답을 통한 데이터 갱신

253자
3분

강의 목차

서버의 객체를 갱신하는 뮤테이션을 다룰 때, 새로운 객체가 뮤테이션 응답으로 자동 반환되는 경우가 많습니다. 이미 가지고 있는 데이터를 위해 불필요한 네트워크 요청을 하지 않고, 뮤테이션 함수가 반환한 객체를 활용해 기존 쿼리를 즉시 갱신할 수 있습니다. 이를 위해 Query Client의 setQueryData 메서드를 사용합니다.

typescript
const queryClient = useQueryClient()
 
const mutation = useMutation({
  mutationFn: editTodo,
  onSuccess: (data) => {
    queryClient.setQueryData(['todo', { id: 5 }], data)
  },
})
 
mutation.mutate({
  id: 5,
  name: '빨래하기',
})
 
// 아래 쿼리는 성공적인 뮤테이션의 응답으로 갱신됩니다
const { status, data, error } = useQuery({
  queryKey: ['todo', { id: 5 }],
  queryFn: fetchTodoById,
})
 
typescript
const queryClient = useQueryClient()
 
const mutation = useMutation({
  mutationFn: editTodo,
  onSuccess: (data) => {
    queryClient.setQueryData(['todo', { id: 5 }], data)
  },
})
 
mutation.mutate({
  id: 5,
  name: '빨래하기',
})
 
// 아래 쿼리는 성공적인 뮤테이션의 응답으로 갱신됩니다
const { status, data, error } = useQuery({
  queryKey: ['todo', { id: 5 }],
  queryFn: fetchTodoById,
})
 

재사용 가능한 뮤테이션에 onSuccess 로직을 연결하고 싶다면, 다음과 같이 커스텀 훅을 만들 수 있습니다:

typescript
const useMutateTodo = () => {
  const queryClient = useQueryClient()
 
  return useMutation({
    mutationFn: editTodo,
    // `mutate` 함수가 받는 변수 객체가 두 번째 인자임에 주목하세요
    onSuccess: (data, variables) => {
      queryClient.setQueryData(['todo', { id: variables.id }], data)
    },
  })
}
 
typescript
const useMutateTodo = () => {
  const queryClient = useQueryClient()
 
  return useMutation({
    mutationFn: editTodo,
    // `mutate` 함수가 받는 변수 객체가 두 번째 인자임에 주목하세요
    onSuccess: (data, variables) => {
      queryClient.setQueryData(['todo', { id: variables.id }], data)
    },
  })
}
 

불변성

setQueryData를 통한 갱신은 반드시 불변 방식으로 수행해야 합니다. 캐시에서 가져온 데이터를 직접 수정하여 캐시에 쓰려고 하지 마세요. 처음에는 동작할 수 있지만, 나중에 미묘한 버그를 유발할 수 있습니다.

typescript
queryClient.setQueryData(['posts', { id }], (oldData) => {
  if (oldData) {
    // ❌ 이렇게 하지 마세요
    oldData.title = '새 게시물 제목'
  }
  return oldData
})
 
queryClient.setQueryData(
  ['posts', { id }],
  // ✅ 이렇게 하세요
  (oldData) =>
    oldData
      ? {
          ...oldData,
          title: '새 게시물 제목',
        }
      : oldData,
)
 
typescript
queryClient.setQueryData(['posts', { id }], (oldData) => {
  if (oldData) {
    // ❌ 이렇게 하지 마세요
    oldData.title = '새 게시물 제목'
  }
  return oldData
})
 
queryClient.setQueryData(
  ['posts', { id }],
  // ✅ 이렇게 하세요
  (oldData) =>
    oldData
      ? {
          ...oldData,
          title: '새 게시물 제목',
        }
      : oldData,
)
 

이 방법을 통해 데이터의 일관성을 유지하고 예측 가능한 애플리케이션 상태를 보장할 수 있습니다. 불변성을 지키면 버그를 줄이고 코드의 가독성과 유지보수성을 높일 수 있습니다.

YouTube 영상

채널 보기
존 매카시가 들려주는 인공지능의 탄생 이야기
NestJS 커스텀 데코레이터, createParamDecorator 사용 | NestJS 가이드
함수 객체의 보편적 구성 | 프로그래머를 위한 카테고리 이론
class-validator 와 DTO | NestJS 가이드
매번 ValidationPipe 복붙하세요? NestJS 전역 파이프로 한 번에 해결하기 | NestJS 가이드
함수 타입과 Hom-Set 이해하기 | 프로그래머를 위한 카테고리 이론
NestJS 인터셉터에서 map 연산자로 응답을 변환하는 방법 | NestJS 가이드
API 응답 지연과 복잡한 에러, NestJS 인터셉터로 관리하는 방법 | NestJS 가이드