-
Notifications
You must be signed in to change notification settings - Fork 0
검색 UX 개선
Ji Ho Jun edited this page Feb 20, 2026
·
2 revisions
본 문서에서는 모임 검색, 사용자 검색, 피드 페이지 등에서 발생하던 비동기 상태 처리 관련 UX 버그(레이아웃 점프, 화면 깜빡임, 오문구 노출)의 원인과 개선 과정을 정리합니다.
- 모임 검색: 상태 관리 구조화 및 플래시 현상 제거
- 모임 검색: 레이아웃 점프 수정 및 자연스러운 전환
- 사용자/최근 검색어: 초기 로딩 시 "결과 없음" 플래시 수정
- 피드 페이지: 초기 진입 시 흰 화면(White Flash) 제거
문제 상황
- 기존에는
isSearching,isFinalized2개의 boolean 조합으로 상태를 관리하여, 전이 타이밍에 따라 "검색 중입니다"와 "검색 내용이 없습니다"가 의도치 않은 순서로 노출되는 Race Condition이 발생했습니다. - 단일
useEffect에서 검색어, 필터, 카테고리 등을 모두 감시하여 Enter 입력 직후나 타이핑 시 중간 상태가 렌더링되며 "검색 중..." 문구가 짧게 깜빡거리는(Flash) 현상이 있었습니다.
해결 방안
-
3단계 상태 모델 도입: 단일 Union 타입(
SearchStatus:'idle' | 'searching' | 'searched')을 도입하여 상태를 명확히 구분했습니다. -
Effect 분리: 렌더링 파이프라인 안정화를 위해
useEffect를 역할별(검색어 감시 / 필터 감시)로 분리하고, 불필요한 중간 렌더링을 차단했습니다.
UX 개선 전/후 비교
1.mov
1-1.mov
🛠 핵심 코드 보기
// GroupSearch.tsx
type SearchStatus = 'idle' | 'searching' | 'searched';
const [searchStatus, setSearchStatus] = useState<SearchStatus>('idle');
// Effect를 역할별로 분리하고 keepPrevious=true 적용
useEffect(() => {
if (searchStatus !== 'searched') return;
// ... 검색어 변경 시 로직 (searchFirstPage 호출 시 keepPrevious: true 전달)
}, [searchStatus, searchTerm]);
useEffect(() => {
if (searchStatusRef.current !== 'searched') return;
// ... 필터/카테고리 변경 시 로직 (searchFirstPage 호출 시 keepPrevious: true 전달)
}, [selectedFilter, category]);문제 상황
- 마감임박순 ↔ 인기순 필터나 카테고리를 변경할 때
setRooms([])가 먼저 실행되어 목록이 한 프레임 비워지고 레이아웃이 위아래로 튀는 현상이 있었습니다.
해결 방안
-
keepPrevious옵션 도입: 데이터 페칭 함수에keepPrevious파라미터를 추가해 최초 검색 시에만 리스트를 초기화하도록 제어했습니다. -
Opacity Fade 효과: 기존 결과가 있는 상태에서 재검색 중일 때(
isRefetching), 목록을 숨기지 않고 투명도(opacity: 0.45)를 낮춰 갱신 중임을 시각적으로 부드럽게 표현했습니다.
🛠 핵심 코드 보기
// GroupSearchResult.tsx & styled.ts
const isRefetching = isLoading && mapped.length > 0;
// ...
export const Content = styled.div<{ isRefetching?: boolean }>`
opacity: ${({ isRefetching }) => (isRefetching ? 0.45 : 1)};
transition: opacity 0.15s ease;
`;문제 상황
- 사용자 검색 첫 입력 직후나 최근 검색어 API 응답 전(빈 배열 상태)에 "찾는 사용자가 없어요", "최근 검색어가 아직 없어요" 문구가 먼저 노출되었습니다.
해결 방안
-
isEmpty판단 로직에type !== 'searching'가드를 추가하고, 최근 검색어 컴포넌트에isLoadingprop을 주입하여 미확정/로딩 상태일 때는 "검색 중...", "불러오고 있습니다" 메시지를 우선 노출하도록 수정했습니다.
UX 개선 전/후 비교
사용자 검색 개선 전 (Before)
4.mov
사용자 검색 개선 후 (After)
4-1.mov
최근 검색어 개선 전 (Before)
4-2.mov
최근 검색어 개선 후 (After)
4-3.mov
🛠 핵심 코드 보기
// UserSearchResult.tsx
// 'searching' 상태에서는 결과가 없어도 빈 메시지를 노출하지 않음
const isEmpty = searchedUserList.length === 0 && type !== 'searching';문제 상황
-
MyFeedPage/OtherFeedPage진입 시 API 응답 대기 시간 동안 빈 컴포넌트(<></>)가 반환되어 앱의 기본 배경(흰색)이 짧게 노출되었습니다.
해결 방안
- 로딩 중에도 기존 다크 테마 배경색상과 뒤로가기 헤더를 유지하는
LoadingScreen을 렌더링하여 자연스러운 페이지 트랜지션을 구현했습니다.
UX 개선 전/후 비교
개선 전 (Before)
5.mov
개선 후 (After)
5-1.mov
- 전체 팀 깃허브 https://github.com/THIP-TextHip
- Web 저장소 https://github.com/THIP-TextHip/THIP-Web