본문 바로가기

REACT/RTK

RTK의 updateQueryData와 onQueryStarted를 쉽게 이해하기

728x90

드래그앤드랍으로 리스트 순서를 변경할 때 종종 깜박임 현상이 발생한다.

예를 들어, A, B, C라는 객체 리스트에서 CA 앞으로 옮긴다고 하자. 기대하는 화면 순서는 [C, A, B]이다.

  1. 사용자가 CA 앞으로 드래그앤드랍 → 화면에는 [C, A, B]가 표시된다.
  2. 순서 변경 API가 호출된다.
  3. 아직 API 응답이 도착하지 않은 상태에서는 기존 리스트 상태가 다시 화면에 반영되어 [A, B, C]로 돌아간다.
  4. API 응답을 받은 후에야 리스트가 다시 [C, A, B]로 업데이트 된다.

결과적으로 1번과 3번 사이에 상태가 왔다갔다하며 깜박임이 발생한다.

이 문제를 해결하기 위해서는 2번 API 호출 시점에 로컬 상태를 즉시 업데이트해주면 된다.

RTK에서 제공하는 onQueryStartedupdateQueryData가 바로 이 역할을 담당한다.

orderApi: build.mutation({
  query: data => ({ url: '/test/order', data }),
  invalidatesTags: [{ type: 'OBJECT', id: 'LIST' }],
  async onQueryStarted({ updateList }, { dispatch, queryFulfilled }) {
    const patchResult = dispatch(
      testApi.util.updateQueryData('objectList', { id }, draft => {
        for (const update of updateList) {
          const id = update.id;
          const orderIdx = update.order;
          const index = draft.findIndex(item => item.id === id);
          draft[index].order = orderIdx;
        }
        draft.sort((a, b) => a.order - b.order);
      }),
    );
    try {
      await queryFulfilled;
    } catch {
      patchResult.undo();
    }
  },
}),

onQueryStarted란?

mutation이 시작된 후에 캐시 데이터를 즉시 업데이트하고 싶을 때 사용하는 콜백이다.

사용자가 변경 요청을 보냈을 때, 서버 응답을 기다리지 않고도 화면에 바로 변화를 보여주어 즉각적인 반응성을 제공하는 데 유용하다.

Optimistic Update 동작 방식

  • 1. 쿼리 또는 뮤테이션이 시작되면 onQueryStarted가 실행된다.
  • 2. 내부에서 api.util.updateQueryData를 디스패치하여 캐시를 수동으로 업데이트한다.
  • 3. 만약 서버 요청이 실패하면, 이전 상태로 롤백하기 위해 .undo()를 호출하거나, 캐시 무효화로 재요청한다.

즉, “내가 먼저 화면에 반영해두고, 혹시 서버가 문제 생기면 다시 돌려놓는” 방식이다.

함수 인자 설명

  • arg : API 호출 시 전달하는 파라미터.
  • 두 번째 인자는 { dispatch, queryFulfilled, getState, ... } 형태의 객체로, thunk API에서 제공한다.
  • queryFulfilled는 Promise이며, 서버 응답 성공 또는 실패를 기다릴 수 있다.

이 패턴 덕분에, 사용자 경험을 깔끔하게 유지하며 비동기 작업의 딜레이를 효과적으로 처리할 수 있다.

 

728x90
반응형