Skip to content

Conversation

@tkyoun0421
Copy link
Contributor

@tkyoun0421 tkyoun0421 commented Jun 26, 2025

개요

프로젝트 검색 기능의 전반적인 사용자 경험을 개선하고, 검색 히스토리 기능을 추가하며, 코드 구조를 체계적으로 리팩토링했습니다. 특히 모바일 환경에서의 사용성을 크게 향상시키고, 코드베이스의 가독성과 유지보수성을 대폭 개선했습니다.

변경 사항

  • 새로운 기능 추가
  • 버그 수정
  • 리팩토링
  • 문서 수정

구현 내용

🚀 새로운 기능

  • 검색 히스토리 기능: 로컬 스토리지 기반 검색 기록 저장, 네이버 스타일 드롭다운으로 직관적인 UX 제공
  • 검색 히스토리 관리: 개별 삭제, 전체 삭제, 히스토리 활성화/비활성화 토글 기능 구현
  • 실시간 활성 필터 카운트: Zustand의 reactive selector를 통해 타이틀 입력 즉시 활성 필터 수 업데이트
  • form 기반 검색: 엔터키와 버튼 클릭 모두 지원하는 접근성 향상된 검색 폼 구현

🎨 UI/UX 개선

  • 스마트 포커스 관리: 클릭어웨이와 내부 요소 클릭을 구분한 정교한 드롭다운 제어
  • 검색 결과 로딩 UI 개선: 중앙 집중형 로딩 스피너로 변경하여 더 깔끔한 로딩 상태 제공
  • 프로젝트 카드 애니메이션 효과: CSS keyframes를 활용한 순차적 fade-in 애니메이션으로 검색 결과 표시 시 자연스러운 UX 구현
  • 모바일 UI 최적화: 검색 버튼, 페이지네이션 버튼 크기 확대 및 터치 친화적 인터페이스로 개선
  • 페이지네이션 지속성: 로딩 중에도 페이지네이션 유지하여 일관된 사용자 경험 제공
  • 필터 레이아웃 개선: 활성 필터 유무에 따른 동적 레이아웃으로 모바일에서 더 나은 공간 활용
  • 프로젝트 상태별 색상 구분: 모집중/모집완료 상태에 따른 동적 색상 적용으로 시각적 구분성 향상

🔧 기술적 개선

  • 검색 기능 강화: 대소문자 구분 없는 클라이언트 사이드 필터링으로 더 유연한 검색 경험
  • 컴포넌트 분리 및 메모이제이션: SearchForm을 SearchInput, SearchFilters, SearchActions, SearchLabels로 세분화하여 성능 최적화
  • 커스텀 훅 분리: useSearchHistory와 useSearchInput 훅으로 로직 캡슐화 및 재사용성 향상
  • 초기 로딩 문제 해결: React Query의 enabled 조건 개선과 기본 필터 값 설정으로 첫 진입 시 즉시 데이터 로딩

📁 코드 구조 리팩토링

  • 파일명 체계화:
    • getFilteredProjectLists.tsprojectSearchApi.ts
    • useGetFilteredProjectLists.tsuseProjectSearchQueries.ts
    • model 폴더 통일: searchFormConfig.ts, searchConstants.ts, searchQueryBuilder.ts
  • 함수명 명확화:
    • getFilteredProjectCountgetProjectsCount
    • getFilteredProjectsByPagegetProjectsByPage
    • SearchFilterBuilderSearchQueryBuilder
  • styled-components 최적화: sx prop 사용 제거 및 shouldForwardProp을 활용한 DOM 오염 방지
  • 사용되지 않는 코드 제거: 커서 기반 페이지네이션 등 불필요한 로직 정리
  • 일관성 있는 네이밍: 파일명과 컴포넌트명 통일, 절대 경로 import로 의존성 명확화

개발 후기 및 개선사항

이번 작업에서 배운 점

  • Zustand의 reactive selector 패턴: 함수 호출 방식이 아닌 hook 방식으로 상태 변경을 실시간 감지하는 방법 습득
  • CSS 애니메이션 vs 라이브러리: react-transition-group 대신 순수 CSS keyframes를 사용하여 더 가볍고 효율적인 애니메이션 구현
  • Material-UI 반응형 디자인: breakpoints와 styled components를 활용한 모바일 최적화 기법
  • 로컬 스토리지 동기화: Zustand persist 미들웨어 없이 수동으로 로컬 스토리지 동기화 구현
  • 컴포넌트 분리 전략: 단일 책임 원칙에 따른 컴포넌트 분리와 props drilling 해결
  • 커스텀 훅 설계: 관련 로직을 그룹화하여 재사용 가능한 훅으로 추상화
  • MUI styled API의 transient props: $ prefix 대신 shouldForwardProp을 사용한 올바른 props 필터링 방법
  • React Query 최적화: enabled 조건 제거와 기본값 설정을 통한 초기 로딩 개선

어려웠던 점 / 에로사항

  • 2번 클릭 문제 해결: React 상태 업데이트의 비동기 특성과 React Query 캐싱으로 인한 복잡한 디버깅 과정
  • TransitionGroup 이슈: Material-UI와 react-transition-group 간 호환성 문제로 순수 CSS 솔루션으로 방향 전환
  • 검색 상태 관리: 여러 컴포넌트 간 검색 상태 동기화 및 실시간 업데이트 구현의 복잡성
  • 포커스 관리 복잡성: 히스토리 드롭다운의 클릭어웨이 vs 내부 클릭 구분 로직 구현의 어려움
  • 메모이제이션 최적화: 불필요한 리렌더링 방지를 위한 적절한 memo와 useCallback 적용 지점 찾기
  • 타입 안전성: TypeScript 환경에서 Zustand 스토어와 커스텀 훅의 타입 정의
  • 대규모 리팩토링: 여러 파일에 걸친 import 경로 변경과 함수명 변경 시 의존성 추적의 복잡성
  • MUI API 변화: styled-components와 MUI의 호환성 이슈 및 올바른 props 전달 방법 학습

다음에 개선하고 싶은 점

  • 검색 결과 캐싱 최적화: React Query의 더 세밀한 캐싱 전략으로 성능 개선
  • 히스토리 기능 확장: 검색 필터까지 포함한 히스토리 저장 및 복원
  • 무한 스크롤: 페이지네이션 대신 무한 스크롤로 더 나은 모바일 UX 제공
  • 검색 성능 최적화: 디바운싱과 서버 사이드 검색을 통한 대용량 데이터 처리
  • A11y 개선: 스크린 리더 지원 및 키보드 내비게이션 강화

팀원들과 공유하고 싶은 팁

  • Zustand reactive selector: useStore((state) => computed_value) 패턴으로 계산된 값도 reactive하게 만들 수 있음
  • Material-UI 모바일 최적화: useMediaQuery와 조건부 props로 모바일/데스크톱 다른 사이즈 적용 가능
  • CSS animation delay: animationDelay: \${index * 0.1}s`` 패턴으로 순차적 애니메이션 간편 구현
  • 불필요한 라이브러리 지양: 간단한 애니메이션은 순수 CSS가 더 가볍고 성능 좋음
  • 로컬 스토리지 동기화: getInitialState 패턴으로 새로고침 시에도 상태 유지 가능
  • 컴포넌트 분리 기준: 비즈니스 로직과 UI 로직을 분리하고, 단일 책임 원칙 준수
  • 포커스 관리: data-* 속성과 closest() 메서드로 복잡한 포커스 로직 간단히 구현
  • MUI styled props: shouldForwardProp으로 DOM에 전달되지 않아야 할 props 필터링
  • 파일명 일관성: 도메인별 prefix를 통한 체계적인 파일 구조 관리
  • React Query 기본값: enabled 조건 대신 기본 필터 값 설정으로 더 자연스러운 UX 제공
  • 코드 정리: 사용되지 않는 코드를 주기적으로 제거하여 번들 크기 최적화

코드 품질 개선 성과

  • 가독성: 명확한 파일명과 함수명으로 코드 의도 파악 용이성 향상
  • 유지보수성: 컴포넌트 분리와 커스텀 훅을 통한 관심사 분리로 수정 범위 최소화
  • 성능: 불필요한 리렌더링 제거와 메모이제이션으로 렌더링 성능 개선
  • 타입 안전성: 명시적 타입 정의와 린트 에러 해결로 런타임 오류 예방
  • 일관성: 전체 프로젝트의 코딩 컨벤션 통일로 개발 효율성 증대

@tkyoun0421 tkyoun0421 self-assigned this Jun 26, 2025
@tkyoun0421 tkyoun0421 added type: feat 새로운 기능 개발 type: bug 버그 수정 type: refactor 코드 리팩토링 labels Jun 26, 2025
@vercel
Copy link

vercel bot commented Jun 26, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
project-jam ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 26, 2025 7:26pm

Copy link
Contributor

@czmcm5 czmcm5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

히스토리가 생겼군요! 멋집니다 💪

</ResultsHeader>

{isLoading ? (
renderLoadingState()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renderLoadingState는 왜 이런식으로 구현되어있는지 여쭐 수 있을까요? 😀

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컴포넌트로 빼는건데 그런식으로 이름이 지어졌네요..👀
수정하겠습니다 감사합니다 🙇

</EmptyState>
)}

{isError && (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isLoading 검사식부터 , !isLoading && !isError && projects.length === 0, isError 는 서로 겹침이 없이 랜더되는 것으로 보이는데 맞을까요?
이 부분은 묶어서 return하는 편이 모든 3가지의 경우를 일일히 검사하지 않아도 되고 가독성 측면에서도 더 좋아보입니다 😇

Copy link
Contributor Author

@tkyoun0421 tkyoun0421 Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞습니다! 해당 사항 포함해서 다시 올리겠습니다 🙇 감사합니다!!

Copy link
Contributor

@namee-h namee-h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

엄청 열일하셨네요! ㅎㅎ 짱이에욥! 👍

@tkyoun0421 tkyoun0421 merged commit ad62cc7 into develop Jun 27, 2025
2 checks passed
@tkyoun0421 tkyoun0421 deleted the feat/search branch June 27, 2025 04:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: bug 버그 수정 type: feat 새로운 기능 개발 type: refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants