[TIL] 240624 (TypeScript 주차 시작 / optimistic update를 useMutation으로 refactoring)

·2024년 6월 24일

TIL

목록 보기
79/268
post-thumbnail

🥞 오늘 한 일

  • 주특기 플러스 주차(TypeScript) 발제
  • 타입스크립트 강의
    • 1-5~9, 2-1~8 수강 (1,2주차 완강)
    • 3-1~4 수강
  • 스탠다드반 타임어택
    • useState, useEffect 로 json-server와 통신하는 투두리스트를 Tanstack Query 로 리팩터링하기
    • try/catch/finally 로 구현된 좋아요 UI optimistic update 를 useMutation 으로 리팩터링하기
  • 스탠다드반 강의
    • 11주차 강의 Optimistic Update 복습
  • 팀 변경
    • 팀 노션 작성
    • 팀장 선출
  • 알고리즘 강의

주특기 플러스 주차 발제 및 팀 변경

오늘은 새로운 주차가 시작되는 날이었고, 팀 역시 변경되었다. 드디어(?) 사전캠프 때 같은 팀이셨던 분들 중 한 분이 다시 팀이 되어 기쁜 날이었다. 그리고 이번 팀에서 팀장을 선출하다가, 일단 아무도 지원자가 안 계셨고, 한 번 쯤은 해보고 싶었는데 최종 때 팀장 선출 방식이 어떻게 될지 몰라서 이번에 내가 지원하여 팀장이 되었다! 안 했으면 후회했을 것 같아서, 하길 잘했다고 생각이 든다.

🍽️ 트러블 슈팅

스탠다드반 타임어택

이번 스탠다드반 타임어택에서 두 문제가 있었는데, 첫번째 문제는 큰 어려움이 없었으나 두번째 문제에서 어려움을 겪었다.

try/catch/finally 로 구현된 좋아요 UI optimistic update 를 useMutation 으로 리팩터링하기

아직 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에 대한 이해도를 높였다.

🍪 배운 것

타입스크립트 강의

  • TypeScript 등장 배경
  • TypeScript를 배우면 할 수 있는 것
  • TypeScript 개발환경 구축
  • 컴파일러, tsc
  • tsconfig.json
  • d.ts
  • 타입
    • 기본 타입
    • const, readonly

🍴 돌아보기

타입스크립트 강의가 예상과 조금 달라서, 이번 주차에 조금은 더 집중을 해야겠다는 생각이 들었다. (외부 강의가 필요할 수도 있겠다는 생각에) 우선, 그래도 강의는 다 듣고 과제를 진행하며 배우는 걸 목표로 해야겠다!

🍳 내일 할 일

  • 타입스크립트 강의 완강 (무조건)
  • 타입스크립트 개인과제 시작
profile
웹 프론트엔드 개발자

0개의 댓글