👉 프로젝트 기간: 22년 6월 20일 ~ 22년 7월 1일
👉 프로젝트 명: WENEIGE
👉 프로젝트 소스: Laneige 홈페이지
👉 프로젝트 구성원: 프론트엔드 4명, 백엔드 1명
홈페이지의 최종 결과물(용량 문제상으로 빨리감기...)
프로젝트 결과 발표 사진
프로젝트간 사용한 협업 툴
Trello
Notion
1️⃣ 메인페이지 내 Carousel 기능 구현하기
2️⃣ 검색창 및 검색기능 구현하기
Carousel이 렌더링 되는 부분
<div
className="inner"
style={{ transform: `translateX(-${activeIndex * 100}%)` }}
>
{carouselData.map(({ id, img, alt }) => {
return (
<div className="carouselItem" key={id}>
<img alt={alt} src={img} />
</div>
);
})}
</div>
Indicator버튼이 렌더링 되는 부분
{carouselData.map((el, index) => {
return (
<button
key={index}
className={`choose${index === activeIndex ? ' active' : ''}`}
onClick={() => {
updateIndex(index);
}}
/>
);
})}
검색기능 구현하기
- 최초에는 Nav에 검색창을 조건부 렌더링으로 searchIcon을 클릭했을 때 보여지게 되는걸로 세팅했으나 팀원들과 상의 하에 검색기능은 메인페이지에서만 활용하기로 결정하여 Nav에서 메인페이지 Carousel 하단으로 이동하였다.
/* 상품데이터를 담기위한 state 생성 */
const [productData, setProductData] = useState([]);
/* 상품데이터를 불러오기 위해 백엔드와의 소통 과정 */
useEffect(() => {
fetch(API.PRODUCTS)
.then(res => res.json())
.then(data => {
setProductData(data.product_detail);
});
}, []);
/* 받아온 데이터를 기반으로 검색기능에 활용하기 위해 가공 */
const sortedItems = productData.filter(item => {
return item.kor_name.includes(searchInputValue);
});
<button onClick={showList}>{buttonTitle}</button>
{isShowOptions && (
<SortButtonOptions
showOptions={setIsShowOptions}
titleChange={setButtonTitle}
sortAscByLetter={sortAscByLetter}
sortDescByPrice={sortDescByPrice}
/>
)}
/* 가나다 순으로 정렬하는 함수 */
const sortAscByLetter = () => {
let listSortedByKoreanAlphabet = [...productData].sort((a, b) =>
a.kor_name > b.kor_name ? 1 : -1
);
setProductData(listSortedByKoreanAlphabet);
};
/* 가격 순으로 정렬하는 함수 */
const sortDescByPrice = () => {
let listSortedByPrice = [...productData].sort((a, b) =>
b.price > a.price ? 1 : -1
);
setProductData(listSortedByPrice);
};
export const CarouselItem = ({ children, width }) => {
return (
<div className="carouselItem" style={{ width: width }}>
{children}
</div>
);
};
const Carousel = ({ children }) => {
const [activeIndex, setActiveIndex] = useState(0);
return (
<div className="carousel">
<div
className="inner"
style={{ transform: `translateX(-${activeIndex * 100}%)` }}
>
{React.children.map(children, (child, index) => {
return React.cloneElement(child, { width: "100%" });
})}
</div>
children
을 토대로 cloneElement
를 하는 방식이 매우 생소했다./main/search
라는 path를 가진 컴포넌트를 하나 더 만들어야 되는 상황이었다./* 최초 가나다 순 정렬 기능 구현 */
const abcSort = () => {
let abcSorting = [...productData];
let abcCompare = key => (a, b) => {
return a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0;
};
abcSorting.sort(abcCompare('title'));
setProductData(abcSorting);
};
/* 최초 가격 순 정렬 기능 구현 */
const priceSort = () => {
let priceSorting = [...productData];
let priceCompare = key => (a, b) => {
return a[key] < b[key] ? 1 : a[key] > b[key] ? -1 : 0;
};
priceSorting.sort(priceCompare('price'));
setProductData(priceSorting);
};
/* children으로 받지않고 데이터를 직접받아 map을 돌려 기존에 CarouselItem이라는
불필요한 컴포넌트를 삭제했다. */
{carouselData.map(({ id, img, alt }) => {
return (
<div className="carouselItem" key={id}>
<img alt={alt} src={img} />
</div>
);
})}
const sortedItems = productData.filter(item => {
return item.kor_name.includes(searchInputValue);
});
최초에 작성한 함수가 가독성이 떨어지고 불필요하게 배열로 접근할 필요가 없었는데 Live Code Review때 멘토의 조언으로 이렇게 복잡하게 할 필요 없이 간단하게 하는 방법이 있다는 설명을 들었다.
/* 가나다 순으로 정렬하는 함수 */
const sortAscByLetter = () => {
let listSortedByKoreanAlphabet = [...productData].sort((a, b) =>
a.kor_name > b.kor_name ? 1 : -1
);
setProductData(listSortedByKoreanAlphabet);
};
/* 가격 순으로 정렬하는 함수 */
const sortDescByPrice = () => {
let listSortedByPrice = [...productData].sort((a, b) =>
b.price > a.price ? 1 : -1
);
setProductData(listSortedByPrice);
};
처음에 mock-data를 학습했을 때 데이터가 무조건 mock-data형식으로 들어오게 될 줄 알고 fetch를 해서 데이터를 받아오는 것을 신경안썼었다.
// 원래는 이러한 형태로 데이터를 만들어 연습했으나...
[
{
"id": 1,
"img": "/images/main/시그니처 브로우 펜슬.jpeg",
"title": "시그니처 브로우 펜슬",
"price": "39000원",
"hashtxt1": "#Meets Arts",
"hashtxt2": "#Artist NOVO"
},
{
"id": 2,
"img": "/images/main/리퀴드 아이라이너.jpeg",
"title": "리퀴드 아이라이너",
"price": "28000원",
"hashtxt1": "#나만의 네오",
"hashtxt2": "#톤떡궁합"
},
]
// 실제로 오는 데이터는 이러한 형식이었다.
product_detail: {
[
{
"id": 1,
"img": "/images/main/시그니처 브로우 펜슬.jpeg",
"title": "시그니처 브로우 펜슬",
"price": "39000원",
"hashtxt1": "#Meets Arts",
"hashtxt2": "#Artist NOVO"
},
{
"id": 2,
"img": "/images/main/리퀴드 아이라이너.jpeg",
"title": "리퀴드 아이라이너",
"price": "28000원",
"hashtxt1": "#나만의 네오",
"hashtxt2": "#톤떡궁합"
},
]
}
1️⃣ 사람들이 있는 공간에서는 소통은 필수다!
2️⃣ 안됀다고 말로만 하지 말고 스스로 해결방법을 찾아내자!
3️⃣ 모든 답은 가까이 있다!
4️⃣ 내가 설명을 한다해서 많이 안다는 것이 아니다! 뭐든지 항상 궁금해 해야한다!