📄Today I Learned
연락처 즐겨찾기 기능 트러블 슈팅
영진학생
2025. 6. 10. 21:02
최종 프로젝트 기간 중간에 유저 테스트를 진행 중 피드백을 받았다.
그래서 즐겨찾기 기능 구현이 필요하다고 생각이 들었음
- 피드백 내용: "내가 찾고싶은 사용자를 리스트에서 찾는 데 시간이 오래 걸린다."
30명의 사용자 테스트 후 DB 분석 결과, 전체 연락처 중 특정 연락처만 반복해서 조회하는 패턴 발견했다
💡기능 구현 방법
1. 데이터베이스 구조 활용
기존 contacts 테이블의 is_pinned 컬럼(Boolean) 활용하여 즐겨찾기 상태를 관리하게 함
2. 백엔드 API 구현
contacts 테이블에 boolean 값을 변경할 업데이트 함수를 생성
// 핀 업데이트 함수
export const mutateUpdateContactPin = async (contactId: string, isPinned: boolean) => {
try {
const { data, error } = await supabase
.from('contacts')
.update({ is_pinned: isPinned })
.eq('contacts_id', contactId)
.select();
if (error) {
throw error;
}
return data;
} catch (error) {
console.error('연락처 핀 업데이트 실패:', error);
throw error;
}
};
3. Tanstack Query를 활용한 상태 관리
// Pin 업데이트 뮤테이션
const pinMutation = useMutation({
mutationFn: ({ contactId, isPinned }: { contactId: string; isPinned: boolean }) =>
mutateUpdateContactPin(contactId, isPinned),
onSuccess: () => {
// 성공 시 연락처 목록 갱신 (새로고침 없이 실시간 업데이트)
queryClient.invalidateQueries({ queryKey: ['contacts', TEST_USER_ID] });
}
});
3-1. 연락처 분리 및 정렬 로직
// 핀된 연락처와 일반 연락처 분리
const { pinnedContacts, regularContacts } = useMemo(() => {
const pinned = contacts.filter(contact => contact.is_pinned);
const regular = contacts.filter(contact => !contact.is_pinned);
return { pinnedContacts: pinned, regularContacts: regular };
}, [contacts]);
3-2. Pin 버튼 UI 구현
// 호버 효과를 위한 상태 관리
const [isPinHovering, setIsPinHovering] = useState(false);
// Pin 토글 핸들러
const handlePinClick = (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
onTogglePin(contact.contacts_id, !contact.is_pinned);
};
3-3. 조건부 스타일링 적용
<button
onClick={handlePinClick}
onMouseEnter={() => setIsPinHovering(true)}
onMouseLeave={() => setIsPinHovering(false)}
className={`mr-5 transition-opacity duration-200 ${
contact.is_pinned
? 'text-gray-800'
: isPinHovering
? 'opacity-70'
: 'opacity-20'
}`}
aria-label={contact.is_pinned ? "즐겨찾기 해제" : "즐겨찾기 추가"}
>
<MapPinSimple size={24} weight={contact.is_pinned ? "fill" : "regular"} />
</button>
UI/UX 개선
연락처 목록 구조
- 고정됨 section: 즐겨찾기된 연락처들을 상단에 별도 섹션으로 표시
- 리스트 section: 일반 연락처들을 하단에 표시
사용자 경험 개선
- 시각적 피드백: Pin 상태에 따른 아이콘 변화
- 호버 효과: 비활성 상태에서도 호버 시 시각적인 효과를 줌
그리고 실시간으로 리스트를 업데이트 해주기 위해 Tanstack Query의 쿼리 무효화를 사용함
- Tanstack Query의 invalidateQueries를 활용하여 새로고침 없이 즉시 UI 반영
- 사용자가 Pin 버튼 클릭 시 즉시 화면 업데이트 경험 제공할수 있게 만듬
효율적인 상태 분리를 위해
- useMemo를 활용하여 연락처 데이터 분리 로직 최적화
- 불필요한 재렌더링 방지
각 리스트 안에 즐겨찾기 버튼이 있다보니 이벤트 버블링을 제어할 필요도 있었다.
- e.preventDefault()와 e.stopPropagation()으로 Pin 버튼과 연락처 선택 이벤트 분리
🎯 배운 점
이번에 추가한 기능을 통해 사용자 피드백이 중요하다는 걸 느꼈다. 내가 예상하지 않은 부분도 유저 테스트를 통해 발견할수 있었고 또 DB 사용 패턴 분석을 통해서 구체적인 해결 방향도 발견할 수 있었다.