
오늘은 새로운 주차가 시작되는 날이었고, 팀 역시 변경되었다. 드디어(?) 사전캠프 때 같은 팀이셨던 분들 중 한 분이 다시 팀이 되어 기쁜 날이었다. 그리고 이번 팀에서 팀장을 선출하다가, 일단 아무도 지원자가 안 계셨고, 한 번 쯤은 해보고 싶었는데 최종 때 팀장 선출 방식이 어떻게 될지 몰라서 이번에 내가 지원하여 팀장이 되었다! 안 했으면 후회했을 것 같아서, 하길 잘했다고 생각이 든다.
이번 스탠다드반 타임어택에서 두 문제가 있었는데, 첫번째 문제는 큰 어려움이 없었으나 두번째 문제에서 어려움을 겪었다.
아직 optimistic update에 대한 이해도가 높지 않았기 때문에, 참조로 주어진 아래 코드를 가져다 쓰려고 했다.
const queryClient = useQueryClient()
useMutation({
mutationFn: updateTodo,
// When mutate is called:
onMutate: async (newTodo) => {
// Cancel any outgoing refetches
// (so they don't overwrite our optimistic update)
await queryClient.cancelQueries({ queryKey: ['todos'] })
// Snapshot the previous value
const previousTodos = queryClient.getQueryData(['todos'])
// Optimistically update to the new value
queryClient.setQueryData(['todos'], (old) => [...old, newTodo])
// Return a context object with the snapshotted value
return { previousTodos }
},
// If the mutation fails,
// use the context returned from onMutate to roll back
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previousTodos)
},
// Always refetch after error or success:
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
허나 이 코드가 어떤 걸 의미하는지 잘 몰랐고, 결국 어떻게든 기능만 되도록 해서 제출했다.
그리고나서 내 부족함을 많이 깨닫고, 해당 부분의 수업을 다시 들으며 복습했다. 그 다음, 부족하다고 생각된 곳을 채워서 다시 코드를 작성해보았다. 또한 주석을 추가하여 이해한 내용을 바로 볼 수 있도록 했다.
const updateMutation = useMutation({
// 실제로 데이터를 변경하는 로직.
mutationFn: async ({ id, currentLiked }) => {
// 클릭한 id의 liked 상태를 변경한다.
await todoApi.patch(`/todos/${id}`, {
liked: !currentLiked,
});
},
// mutationFn보다 먼저 실행됨
onMutate: async ({ id }) => {
// todos에서 진행 중인 게 있다면 취소.
await queryClient.cancelQueries({ queryKey: ["todos"] });
// 실패할 경우를 대비해 현재 todos의 상태를 저장
const previousTodos = queryClient.getQueryData(["todos"]);
// 아직 실제 데이터에 반영되지는 않았지만, 일단 화면에 반영을 하기 위해 강제로 todos를 바꿔서 하려는 기능(좋아요)이 화면에 적용되도록 한다.
queryClient.setQueryData(["todos"], (prev) =>
prev.map((todo) =>
todo.id === id ? { ...todo, liked: !todo.liked } : todo
)
);
// context를 반환하지만 그 안에 들어갈 previousTodos만 구조 분해 할당으로 return한다.
return { previousTodos };
},
onError: (context) => {
// 에러 발생 시 미리 만들어둔 previousTodos로 다시 todos를 set한다.
queryClient.setQueryData(["todos"], context.previousTodos);
},
onSettled: () => {
// 위의 처리들이 완료되었을 경우 invalidateQueries를 사용해 화면에 바로 적용시킨다.
queryClient.invalidateQueries({ queryKey: ["todos"] });
},
});
이를 통해 이번 타임어택에서 헷갈려 잘못 작성했던 코드를 다시 작성하며 optimistic update에 대한 이해도를 높였다.
타입스크립트 강의가 예상과 조금 달라서, 이번 주차에 조금은 더 집중을 해야겠다는 생각이 들었다. (외부 강의가 필요할 수도 있겠다는 생각에) 우선, 그래도 강의는 다 듣고 과제를 진행하며 배우는 걸 목표로 해야겠다!