Skip to content

[이서라] 스프린트 미션 4#59

Open
shoooongs wants to merge 16 commits into
codeit-sprint-fullstack:basicfrom
shoooongs:react-이서라

Hidden character warning

The head ref may contain hidden characters: "react-\uc774\uc11c\ub77c"
Open

[이서라] 스프린트 미션 4#59
shoooongs wants to merge 16 commits into
codeit-sprint-fullstack:basicfrom
shoooongs:react-이서라

Conversation

@shoooongs

Copy link
Copy Markdown
Collaborator

중고마켓 페이지의 핵심 기능(검색, 필터링, 정렬, 페이지네이션)을 구현하고, 공통 레이아웃 및 반응형 디자인(PC/모바일) 적용과 코드 리팩터링을 진행했습니다.

주요 변경 사항

1. 기능 구현 (Features)

  • 검색 및 필터링: 레이아웃 컴포넌트 구축과 함께 상품 검색 기능 및 전체 상품 필터링 기능을 완성했습니다.
  • 정렬 및 예외 처리: 판매상품 정렬을 위한 메뉴 토글 기능을 구현하고, 엑박(깨진) 이미지 예외 처리를 추가했습니다.
  • 페이지네이션: 페이지네이션 기능을 활성화 상태 로직과 함께 완성했습니다.
  • 반응형 스타일링: 디바이스 크기에 따른 반응형 상품 개수 조정 기능을 구현하고, PC 및 모바일 기준 스타일링을 완료했습니다.

2. 코드 구조 개선 (Refactoring)

  • 로직 분리: 메인 페이지의 복잡도를 낮추기 위해 드롭다운 로직페이지네이션 로직을 각각 독립된 개별 컴포넌트로 분리했습니다.
  • 세부 구현: 모바일 환경에서의 전체상품 필터 기능 세부 로직을 다듬고 최종 리팩터링을 완료했습니다.

@devbini devbini left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🎉 고생많으셨습니다!

검색, 정렬, 페이지네이션, 반응형 pageSize 등등...
목록 페이지에서 필요한 기능을 꽤 많이 구현해주셨어요. 처음 React로 API 목록 페이지를 만들 때는 한 기능만 붙여도 신경 쓸 부분이 많은데, 전체적으로 높은 구조 안정성을 보여준 것 같아요!
의존성 배열 관리 역시 React를 초심적으로 사용할 때 가장 어려운 부분인데, 그 역시 큰 문제가 없는 것 같네요 😊

또 추가로, 기능 단위로 컴포넌트를 나누려는 시도도 좋았고, API baseURL을 공통 axios 인스턴스로 만든 것도 좋은 습관이에요. 특히 이런 axios 인스턴스는 실무에서도 채용하는 방법이랍니다! 이렇게 하는 경우, 나중에 인증 헤더나 공통 에러 처리, timeout 같은 설정이 필요해졌을 때 훨씬 관리하기 쉬워집니다.

다만, 코드만 놓고 보면 실제 빌드나 화면에서 바로 문제가 될 수 있는 부분이 몇 개 있어요, import 경로의 대소문자라던지, 이미지 배열 처리나 API 실패 처리 등 실제 사용자가 어떻게 느낄지를 더 생각 해 주시면 좋겠어요.

전체적으로 기능을 많이 구현하신 만큼, 이제는 "예외 상황에서도 화면이 안정적으로 보이는가"를 같이 챙겨보면 더 좋아질 것 같습니다. 앞으로도 많이 기대가 되는 코드였어요!

파이팅입니다 👍

  • 아, 추가로.. SVG를 인라인코드로 쭉 작성된 게 많던데.. 가능하면 파일로 분리 해 주세요!ㅎㅎ
    유지보수를 넘어 코드 가독성이 떨어지는 원인이 되기도 한답니다!

Comment thread client/src/components/Footer.jsx Outdated
Comment on lines +3 to +4
import IconYT from '../assets/ic_Youtube.svg';
import IconIG from '../assets/ic_Instagram.svg';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🚩 Check Point

조금 위험 해 보이네요.
실제 파일명은 ic_youtube.svg, ic_instagram.svg입니다.

아마.. 제 기억 상 Windows에서는 동작할 수 있지만, Linux 기반 배포 환경에서는 파일을 찾지 못해 빌드가 실패할 수 있어요.

예를 들어, Jenkins 등의 별도 CICD 툴에 들어갔을 때 에러가 날 수도 있답니다.

아무튼, 정리하면-
실제 파일은 소문자이기 때문에 해당 모듈을 찾지 못하고 빌드가 멈출 수 있습니다.

Comment thread client/src/components/ItemList.jsx Outdated
function EachItem ({ item }) {
return (
<li className={styles.eachItem}>
<div className={styles.thumbnail}><img src={item.images} alt={item.name} onError={(e) => (e.target.src = defaultImage)}/></div>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🚩 Check Point

음.. API의 images는 배열인 것 같아요.
그런데 현재는 배열을 그대로 src에 넣고 있네요.

item.images = [
  'https://example.com/a.png',
  'https://example.com/b.png',
]

만약 위처럼 값이 들어오게 되면...
<img src="https://example.com/a.png,https://example.com/b.png">

이런 식으로 HTML 구조가 만들어지게 되어버려요.
이건... 정상적인 이미지 주소가 아니기 때문에 썸네일이 깨질 수 있습니다.

이렇게 사용 할 거라면, 첫 번째 이미지를 명확히 꺼내고, 없으면 기본 이미지를 보여주는 방식이 안전해보여요! 😊

orderBy: 'favorite',
}
});
const { list } = response.data;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🚩 Check Point

현재는 API 요청이 성공한다고 가정하고 바로 response.data를 사용하고 있어요.

예를 들어, 사용자가 페이지에 들어왔는데 네트워크가 잠깐 끊겼다고 해봅시다.

그러면, 지금 구조에서는 axios.get()이 실패하고 이후 코드가 실행되지 않습니다.

그런데 화면에는 "오류가 났다"는 정보가 없어서, 사용자는 상품이 원래 없는 것처럼 이해할 수 있을 것 같아요.

목록 페이지에서는 최소한 로딩/실패 상태를 구분하는 처리가 있으면 좋습니다 😊

너무 어렵게 생각 할 것 없이, try/catch를 이용하기만 해도 충분하지 않을까 싶어요 😊

gap: 1.2rem;
}

@media (max-width:1024) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🚩 Check Point

아마도.. 깜빡하신 것 같아요!
아시다시피- CSS에서 길이 값은 px같은 단위가 항상 필요해요!

<section className="products-list all">
<div className="section-title-header">
<h2 className="section-title">판매 중인 상품</h2>
{isMobile ? (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

☕ Thinking

지금 보면 모바일과 데스크톱의 배치가 달라서 JSX를 분기하고 있는 것 같아요.

이런 구분은 자연스럽긴 한데, 검색 form이라던지, 각종 버튼이나 input 구조가 거의 그대로 반복되는 것 같아요.

이렇게 되면... 당연하게도 수정이 필요할 때 양쪽 다 찾아서 수정해줘야 하는 불상사가 생긴답니다. (거기서 누락되는 것도 있을 수 있구요!)

그래서.. 반복되는 부분들은 별도의 컴포넌트로 묶어서 빼 보는 등의 캡슐화는 어떨까 제안 드려봐요 🤔

Comment on lines +60 to +81
const handleSize = useCallback(() => {
const contentWidth = window.innerWidth;
if (contentWidth < 480 ){
setPageSize(4);
setIsMobile(true);
} else if (contentWidth < 1024 ){
setPageSize(6);
setIsMobile(false);
} else {
setPageSize(10);
setIsMobile(false);
}
},[]);

useEffect(() => {
//처음
handleSize();
//리사이즈했을때 실행하셈
window.addEventListener('resize',handleSize);
//이벤트리스너 지움
return () => window.removeEventListener('resize',handleSize);
},[handleSize]);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

☕ Thinking

window.innerWidth로 플랫폼을 구분하는 코드가 페이지에 들어 있는데,
저희가 React를 다루고 있는 만큼, 이런 size 이벤트 관리같은 환경 감지 로직은 별도 Custom Hook으로 만들어 사용할 수 있지 않을까요?!

setBestItems(list);
},[pageSize]);

console.log('페이지사이즈', pageSize);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤔 Thinking

개발중에 log를 찍는 건 당연히 자연스럽고, 저도 구현 중에는 많이 찍긴 합니다만...

실제 서비스 코드에서도 남아있게 되면, 오히려 실제 오류 로그를 확인할 때 방해가 될 수도 있답니다!

Comment on lines +37 to +41
<li onClick={() => handleSortChange('recent')}>최신순</li>
<li onClick={() => handleSortChange('favorite')}>좋아요순</li>
</ul>
</div>
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

☕ Thinking

지금 드롭다운은 divlionClick을 달아서 동작하고 있네요.
마우스로 클릭하면 동작하지만... 키보드 접근성은 떨어질 수 있습니다.

클릭 가능한 요소는 기본적으로 button을 먼저 고려하는 게 시멘틱 태그를 더 잘 이해하는 부분이 아닐까 싶어요.

또, 커스텀 드롭다운을 직접 구성한다면
aria-expanded같은 속성을 찾아보면 어떨까 싶어요! 😊

항상 이런 고민은 너무 좋은 것 같아요 😊
어떤 요소와 어떤 태그가 UX에 있어 더 좋을지 고민하는 점이요!

@devbini

devbini commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator
  • 아, 그리고... 현재 PR merge 타깃 브랜치가 basic으로 되어있어요.
    제가 수정하려 했으나, 브랜치 명이 한글이라 변경이 어려운 상황입니다.

react-이서라 이름의 브랜치로의 PR을 다시 한번 열어주시면 바로 머지 해 두도록 할게요! 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants