본문 바로가기

[React]

[React] 선반영, 후처리 유저 경험 및 성능 향상 - 낙관적 UI 업데이트 (Optimistic UI Update)

728x90

[React] AbortController와 zustand로 전역 fetch 취소 구현하기 (feat. 카카오 테크)

 

[React] AbortController와 zustand로 전역 fetch 취소 구현하기 (feat. 카카오 테크)

[Express] 레이어드 아키텍쳐 구현하기 (Layered Architecture) [Express] 레이어드 아키텍쳐 구현하기 (Layered Architecture)🚩 소개안녕하세요! 대학생 개발자 주이어입니다!오늘은 레이어드 아키텍쳐 구조화

blog.juyear.dev

이전 글 읽으러 가기!

 

👋 소개

안녕하세요! 대학생 개발자 주이어입니다!

오늘은 낙관적 UI 업데이트 (Optimistic UI Update)에 대해서 정리하고 실제 프로젝트에 적용했던 예제 코드도 같 설명해드릴려고 합니다.


❓ 낙관적 UI 업데이트란?

낙관적 UI 업데이트란 데이터를 처리하기 전에 먼저 UI를 반영하고, 그 후에 데이터를 처리하는 것을 의미합니다.

즉, 사용자가 서버 응답을 기다리지 않고, 변경된 UI를 바로 확인할 수 있기 때문에 사용자 경험면에서 크게 향상됩니다.

 

또한 사용자가 생각하기에 데이터가 빠르게 처리됐다고 느껴 실제 성능은 똑같지만, 향상된 것 같은 효과를 보일 수 있습니다.

그럼 자세한 내용은 밑에 실제 예제를 통해서 설명하도록 하겠습니다.


🧾 기존 방식

  setHeartLoading(true); // 중복 요청 방지
  try {
    await fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/post/heart`, { // 데이터 처리
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        sub: sub,
        postId: id,
      }),
    })
      .then((res) => res.json())
      .then((data) => {
        const updatedSorted = sortedPosts.map((item) => // 데이터 반영
          item.id === id
            ? {
                ...item,
                heart: data === "create" ? item.heart + 1 : item.heart - 1,
              }
            : item
        );
        setSortedPosts(updatedSorted); // UI 반영
        if (data === "create") {
          const added = sortedPosts.find((item) => item.id === id);
          if (added) {
            setSavedPosts((prev) => [...prev, added]);
          }
        } else if (data === "delete") {
          setSavedPosts((prev) => prev.filter((item) => item.id !== id));
          if (curButton === "saved") {
            setSortedPosts((prev) => prev.filter((item) => item.id !== id));
          }
        }
        setHeartLoading(false);
      });
  }

현재 제가 진행중인 프로젝트에서 사용했던 기존 코드 입니다.

코드가 좀 길지만 주석 부분만 보시면,

데이터 처리 -> 데이터 반영 -> UI 반영

위와 같은 순서로 처리되는 것을 알 수 있습니다.

fetch문 이후에 반환된 데이터를 가져와 데이터를 반영하고, 그 이후에 마지막으로 UI를 반영하는 식으로 처리되고 있습니다.

 

보통은 위와 같은 방식으로 처리해도 크게 문제가 되지 않지만, 처리해야 하는 데이터가 자주 발생하는 데이터이고, 해당 데이터를 활용하여 UI 반영을 바로 해야한다면 문제가 생깁니다.

바로 처리되는데 오래 걸린다는 문제점이죠.

 

이럴 경우 사용자가 데이터가 처리되었는지 확인하는데 오래 걸리고, 그럼 사용자 경험 면에서 크게 떨어지게 됩니다.

그래서 사용하는 방식이 바로 낙관적 UI 업데이트 (Optimistic UI Update) 입니다.


 낙관적 UI 업데이트 방식

  setHeartLoading(true); // 중복 요청 방지
  const isSaved = savedPosts.some((item) => item.id === id);
  const updatedSorted = sortedPosts.map((item) => // 데이터 선 반영
    item.id === id
      ? {
          ...item,
          heart: isSaved ? item.heart - 1 : item.heart + 1,
        }
      : item
  );
  setSavedPosts((prev) =>
    isSaved
      ? prev.filter((item) => item.id !== id)
      : [...prev, posts.find((p) => p.id === id)!]
  );
  setSortedPosts(updatedSorted); // UI 선 반영
  try {
    await fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/post/heart`, { // 데이터 처리
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        sub: sub,
        postId: id,
      }),
    })
      .then((res) => res.json())
      .then((data) => {
        if (data === "create") {
          const added = sortedPosts.find((item) => item.id === id);
          if (added) {
            setSavedPosts((prev) => [...prev, added]);
          }
        } else if (data === "delete") {
          setSavedPosts((prev) => prev.filter((item) => item.id !== id));
          if (curButton === "saved") {
            setSortedPosts((prev) => prev.filter((item) => item.id !== id));
          }
        }
      });
  } catch (err) {
    setSortedPosts(sortedPosts); // 오류 발생 시 롤백
  } finally {
    setHeartLoading(false);
  }

위 코드는 기존 코드를 낙관적 UI 업데이트 방식을 적용하여 수정한 코드 입니다.

역시나 코드가 길지만 주석 부분만 보면,

데이터 선 반영 -> UI 선 반영 -> 데이터 처리 -> 문제 시 롤백

위와 같은 방식으로 처리 됩니다.

사용자의 상호작용에 대해서 먼저 된다고 가정하고 데이터를 처리하고, UI도 미리 반영합니다.

그 후 fetch문을 통해 실제 데이터를 처리하게 됩니다.

 

근데 만약 오류가 발생한다면, 기존 데이터로 다시 되돌려 롤백 처리를 하게 됩니다.

 

이렇게 처리한다면 사용자는 상호작용시 빠른 속도로 변경된 UI를 확인할 수 있고,

사용자 경험면에서 크게 향상됩니다. 


📽️ 실제 비교 영상

기존 방식
낙관적 UI 업데이트 방식

위 두 영상을 확인해보시면 얼마나 큰 차이가 나는지 확인이 가능하실 것 같습니다.


😊  마무리

지금까지 낙관적 UI 업데이트 방식에 대해서 간단하게 소개하고, 실제 예제와 영상으로 속도 차이까지 확인해보았습니다.

이러한 방식은 흔히 사용되는 방식이니 프론트엔드 개발자라면 한번씩 읽어보시고 자신의 프로젝트에 적용해보시길 바랍니다!

 

오늘 글은 이렇게 간단하게 마무리 짓도록 하겠습니다!

 

그럼 지금까지 읽어주셔서 감사드리고, 다음에는 더 흥미롭고 유익한 글로 돌아오도록 하겠습니다!

 

💬 함께 공부하고 싶은 내용이 있다면 댓글이나 피드백으로 알려주세요!

 

[TRAIVEL] 개인 맞춤형 여행 일정 생성 플랫폼 TRAIVEL

 

[TRAIVEL] 개인 맞춤형 여행 일정 생성 플랫폼 TRAIVEL

🚩 소개안녕하세요. 대학생 개발자 주이어입니다!오늘은 제가 이번에 진행하는 프로젝트에 대해서 비즈니스 & 마케팅 중심으로 글을 작성해보려고 합니다.흔히 "Product Launch" 라고 불리는 스타

blog.juyear.dev

추천 글 읽으러 가기!

 

https://discord.gg/8Hh8WgM4zp

 

KYT CODING COMMUNITY Discord 서버에 가입하세요!

Discord에서 KYT CODING COMMUNITY 커뮤니티를 확인하세요. 23명과 어울리며 무료 음성 및 텍스트 채팅을 즐기세요.

discord.com

KYT CODING COMMUNITY 가입하기!

728x90