728x90
드래그앤드랍으로 리스트 순서를 변경할 때 종종 깜박임 현상이 발생한다.
예를 들어, A, B, C
라는 객체 리스트에서 C
를 A
앞으로 옮긴다고 하자. 기대하는 화면 순서는 [C, A, B]
이다.
- 사용자가
C
를A
앞으로 드래그앤드랍 → 화면에는[C, A, B]
가 표시된다. - 순서 변경 API가 호출된다.
- 아직 API 응답이 도착하지 않은 상태에서는 기존 리스트 상태가 다시 화면에 반영되어
[A, B, C]
로 돌아간다. - API 응답을 받은 후에야 리스트가 다시
[C, A, B]
로 업데이트 된다.
결과적으로 1번과 3번 사이에 상태가 왔다갔다하며 깜박임이 발생한다.
이 문제를 해결하기 위해서는 2번 API 호출 시점에 로컬 상태를 즉시 업데이트해주면 된다.
RTK에서 제공하는 onQueryStarted
와 updateQueryData
가 바로 이 역할을 담당한다.
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
반응형