사용자가 찜한 모임 목록을 서버에서 불러오는 기능을 구현 중이었다. 처음에는 'hydrated'
상태가 완료되지 않았을 때 로딩 메시지가 한 번 나타나고, 그 뒤로도 'isLoading'
상태에서 또 다른 로딩 메시지가 나타나는 문제가 있었다. 이러한 중복 로딩 표시가 사용자 경험을 저해할 수 있어 해결책을 찾고자 했다.
Zustand로 찜 목록을 관리하는 중, hydration
문제를 해결하기 위해 hydrated 값을 사용하여, 아직 hydration
이 완료되지 않았을 때는 사용자에게 대체 메시지를 보여주는 방식을 구현했다.
그런데 아래 html 요소와 속성을 같게 줘도 글자가 위아래로 움직이는 화면이 나타났다. 그리고 아래와 같은 방법은 실제로 구현하면서도 이 방법은 아니것이라고 확신이 들었다.
처음에는 다음과 같은 코드를 사용했다.
if (!hydrated) {
return (
<div className="flex items-center justify-center h-full min-h-500pxr">
<p className="h-10 text-sm font-medium text-center text-gray-500">찜 목록 확인 중...</p>
</div>
);
}
let content;
if (isLoading) {
content = (
<div className="flex items-center justify-center h-full min-h-500pxr">
<p className="h-10 text-sm font-medium text-center text-gray-500">데이터 불러오는 중...</p>
</div>
);
}
하지만 hydrated
가 false
일 때와 isLoading
상태에서 두 개의 유사한 메시지를 보여주는 동안, 페이지에서 글자가 약간의 차이로 위아래로 움직이는 현상이 발생했다. HTML 구조와 속성은 같았지만, 이러한 화면 변화로 인해 사용자 경험이 떨어진다는 것을 느꼈다. 그리고 이 방법이 최선이 아니라는 확신이 들었다.
따라서 이 문제를 해결하기 위해, 두 상태(hydration과 isLoading)를 통합하여 메시지를 일관되게 유지하고 불필요한 화면 움직임을 방지하는 방식으로 개선할 필요가 있었다.
그리고 실제 목록들은 useQuery를 이용하여 데이터를 요청해서 가져오고 있다.
먼저, react-query
에서 enabled
옵션을 사용해 hydrated
상태가 완료될 때까지 쿼리가 실행되지 않도록 제어했다. 또한, hydrated
가 완료되지 않았을 때와 isLoading
상태를 구분해 로딩 메시지를 한 번만 표시하도록 코드를 수정했다.
useQuery({
queryKey,
queryFn: async () => {
// ...
},
enabled: hydrated, // hydrated가 true일 때만 쿼리 실행
});
if (!hydrated || isLoading) {
return (
<div className="flex items-center justify-center h-full min-h-500pxr">
<p className="h-10 text-sm font-medium text-center text-gray-500">찜 목록 확인 중...</p>
</div>
);
}
이렇게 코드를 수정한 후, 처음 hydration
이 완료되지 않았을 때만 로딩 메시지가 표시되고, 데이터를 불러올 때는 중복된 로딩 메시지가 사라지게 되었다. 결과적으로 사용자 경험이 개선되었다.
이 방법은 다른 비동기 데이터 로딩 상황에서도 쿼리 실행 조건을 제어할 때 유용하다고 생각한다.