
낙관적 UI(Optimistic UI)는
사용자의 행동에 대해 서버 응답을 기다리지 않고 먼저 결과를 화면에 반영하는 전략입니다.
예를 들어 링크를 삭제하거나 폴더 이름을 바꿀 때,
"요청 중입니다…" 메시지를 띄우는 대신
바로 삭제되고 바뀐 것처럼 UI가 반응합니다.
이런 반응 속도는 특히 짧은 집중력과 빠른 흐름에 익숙한 사용자 환경에서 강력한 무기가 됩니다.
링크 드라퍼에서는 다음과 같은 작업에 낙관적 UI를 적극적으로 적용하고 있습니다:
이 작업들은 사용자의 흐름에서 빈번하게 발생합니다.
하나하나 멈춰서 기다린다면 전체 경험이 지체되기 쉽죠.
그래서 저희는 즉시 화면에 반영되도록 처리하고,
서버와의 통신 결과에 따라 성공 시 유지 / 실패 시 롤백 구조로 만들었습니다.
낙관적 UI의 본질은 간단합니다.
"우리는 아직 서버로부터 응답을 받지 않았지만, 됐다고 믿을게요."
이 작은 신뢰는 사용자의 몰입을 극적으로 높입니다.
하지만 이 신뢰가 틀렸을 때, 문제가 시작됩니다.
사용자는 무언가 잘못됐다는 불쾌한 경험을 하게 되고,
서비스에 대한 신뢰를 잃을 수 있습니다.
랑크 드라퍼는 아래와 같은 흐름으로 링크를 저장합니다.
1. 사용자: 클립보드에 있는 링크 붙여넣기(ctrl+v) 혹은 링크 직접입력()
2. 크롤링 서버: 해당 링크에 있는 메타데이터 크롤링
3. API 서버: 2번에서 불러온 메타데이터를 DB에 저장
2번 과정은 타겟 링크의 크롤링 난이도에 따라, 2초 이상 소요되는 경우도 있어
이때는 해당 링크가 표시될 자리에 로딩 애니메이션을 표시합니다.
낙관적 UI가 적용되는 시점은 2번이 끝난 직후입니다.
사용자 UI에 표시할 정보는 이미 다 얻었으니,
내부적으로 DB에 저장하는 과정은 사용자가 기다리게 할 필요가 없는 것입니다.
따라서, DB에 저장하는 과정이 '성공할 것이라 낙관적으로 가정'하고
이 단계를 사용자에게는 기다리지 않게 하는 것입니다.
이렇게 사용자의 체감 로딩을 몇백 밀리세컨드를 단축할 수 있었습니다.
하지만, 모종의 이유로 DB 작업이 실패한 경우에는,
그 일이 일어나기 전의 상태로 복구 시켜야겠죠?
(Zustand + snapshot 기반)
링크 드라퍼는 전역 상태 관리에 Zustand를 사용하고 있으며,
snapshot 기능을 이용해 낙관적 UI 구현을 단순화했습니다.
// store.ts
import { createStore } from 'zustand';
type Link = { id: string; url: string };
type State = {
links: Link[];
setLinks: (links: Link[]) => void;
removeLink: (id: string) => void;
};
export const linkStore = createStore<State>((set) => ({
links: [],
setLinks: (links) => set({ links }),
removeLink: (id) =>
set((state) => ({
links: state.links.filter((link) => link.id !== id),
})),
}));
// 낙관적 삭제 처리
async function deleteLink(linkId: string) {
const snapshot = linkStore.getState().links;
linkStore.getState().removeLink(linkId); // UI 먼저 반영
try {
await fetch(`/api/delete-link?id=${linkId}`, { method: 'DELETE' });
} catch (err) {
console.error('삭제 실패, 롤백합니다');
linkStore.getState().setLinks(snapshot); // 실패 시 복원
}
}
⸻
• ⚡ 즉각적인 반응 → 사용자는 “됐다”고 인지
• 🌊 자연스러운 흐름 유지 → 몰입이 끊기지 않음
• 🌐 네트워크 상태가 불안정해도 UX는 부드럽게 유지
특히 모바일, 느린 환경, 반복 작업에 강력한 효과를 발휘합니다.
⸻
1. 실패 상황에 대한 복원 시나리오 필수
2. 상태의 일관성 보장이 어렵다는 점
3. 사용자에게 실패를 어떻게 알려줄 것인지에 대한 UX 설계 필요
링크 드라퍼에서는 toast.error()를 통해 사용자에게 정확한 피드백도 함께 제공합니다:
toast.error('삭제에 실패했어요. 다시 시도해주세요.');
⸻
링크 드라퍼는 단순한 저장 툴이 아닙니다.
정리하고, 수정하고, 다시 꺼내보게 만드는 링크 관리 도구입니다.
• 🔗 링크 삭제, 폴더 생성/수정 등을 낙관적으로 처리
• 🧠 링크 의미를 기억하게 만드는 메모 기능
• 🌐 폴더를 친구에게 공유 가능
• ⚡ OG 미리보기 자동 불러오기
지금 직접 써보시고,
즉각적인 UI 반응이 얼마나 사용자 흐름에 영향을 주는지 경험해보세요.
⸻
낙관적 UI는 신뢰의 UI입니다.
서버보다 UI가 먼저 믿는 그 순간,
사용자의 경험은 가볍고 유려해집니다.
하지만 그만큼 책임도 커집니다.
속도를 올리려면 신뢰를 설계해야 합니다.
여러분의 서비스엔 낙관적 UI가 적용되어 있나요?
댓글로 공유해 주세요 🙌