항해 99 리액트 3주차 과제는 백과 협업하여 클론코딩하기였습니다. 우선 팀원 모두 커머스 사이트에 관심을 가지고 있었습니다. 일주일이라는 짧은시간에 제작할 수 있는 스코프로 기존에 관심있게 보던 재주 상회
라는 기업의 홈페이지를 주제로 제시하게 되었고, 모두 동의하여 이를 주제로 프로젝트를 진행하게 되었습니다.
- 재주상회의 애니메이션은 굉장히 잘 되있어, 눈에 띄이는 구조였습니다.
- 따라서 이를 최대한 반영하고자 노력하였습니다.
- 특히 스크롤을 내릴 때, 헤더의 변형이 일어나는 부분과 아이템들이 올라오는 기능을 중점적으로 구현하였습니다.
- 헤더는 스크롤을 스크롤 위치를 가져와 일정 위치 이상이면, 변화하도록 제작하였습니다.
- 그러나, 문제는 돔에 건드는 문제가 적용되어 있다는 점입니다. 이부분을 추후 개선하고자 합니다.
스크롤 위치 커스텀 훅import { useState, useEffect } from "react";
const useScrollPosition = () => {
const [scrollPosition, setScrollPosition] = useState(0);
const updateScroll = () => {
setScrollPosition(window.scrollY || document.documentElement.scrollTop);
};
useEffect(() => {
window.addEventListener("scroll", updateScroll);
});
return scrollPosition;
};
export default useScrollPosition;
헤더
return (
<HeaderContainerSecond>
{scrollPosition > 36 && (
<img
src="http://iiinjeju.com/_dj/img/logo.jpg"
alt="iiin 로고"
onClick={() => {
navigate("/");
}}
/>
)}
{categories.map((category) => {
return (
<LinkButton
key={category}
linkName={category}
fontsize={scrollPosition <= 36 ? "1rem" : "0.8rem"}
margin={scrollPosition <= 36 ? "1rem 4rem" : "0.4rem 1.5rem"}
linkTo={`/product/list?category=${category.toLowerCase()}&page=1`}
isHoverNeed={true}
/>
);
})}
<IconContainer>
<div>
<img
src={process.env.PUBLIC_URL + "/imgs/cart.svg"}
alt="cart"
onClick={() => {
navigate("/cart");
}}
/>
<div
onClick={() => {
navigate("/cart");
}}
>
{cartItemCount}
</div>
</div>
</IconContainer>
</HeaderContainerSecond>
);
아이템 fadein 훅
import { useCallback, useEffect } from "react";
import { useRef } from "react";
const useScrollFadeIn = () => {
const dom = useRef();
const handleScroll = useCallback(([entry]) => {
const { current } = dom;
if (entry.isIntersecting) {
current.style.transitionProperty = "opacity transform";
current.style.transitionDuration = "1s";
current.style.transitionTimingFunction = "cubic-bezier(0, 0, 0.2, 1)";
current.style.transitionDelay = "0.1s";
current.style.opacity = 1;
current.style.transform = "translate3d(0, 0, 0)";
}
}, []);
useEffect(() => {
let observer;
const { current } = dom;
if (current) {
observer = new IntersectionObserver(handleScroll, {
threshold: 0.5,
});
observer.observe(current);
return () => observer && observer.disconnect();
}
}, [handleScroll]);
return {
ref: dom,
style: {
opacity: 0,
transform: "translate3d(0, 50%, 0)",
},
};
};
export default useScrollFadeIn;
아이템
const ItemScreen = ({ thumbnailImgUrl, name, price, caption, linkTo }) => {
const animationItem = useScrollFadeIn();
const navigate = useNavigate();
return (
<Container
ref={animationItem.ref}
style={animationItem.style}
onClick={() => {
navigate(linkTo);
}}
>
<img src={thumbnailImgUrl} alt={name}></img>
<div>{name}</div>
<h6>{caption}</h6>
<h5>{numeral(price).format("0,0")}원</h5>
</Container>
);
};