구조 파악하기
미국고전영화 텍스트 밑에 카페 사진과 바다 사진이 있다. 각각의 요소가 원래는 영화 포스터가 자리해야 한다.(저작권 문제로 일단은 보류)
해당 콘텐츠는 첫 화면에서 5개가 보여진다. 콘텐츠 5개의 길이는 1375px이다
오른쪽 버튼을 누르면 요소들이 x축을 기준으로 -1375만큼 왼쪽으로 휙 밀려나게 된다.
다음 콘텐츠들도 똑같이 width
가 1375px이다.
먼저 1375px씩 이동하려면 아래의 스타일링을 부여해야 하는데,,,
중요한 건 1375px씩이다. SCSS에 작성하면 0에서 1375px 이동하고 끝이다.
🙌SCSS로 해결할 수 없으니 이동되는 px을 state로 관리해야 한다.🙌
//MainBox.js
const [slidePx, setSlidePx] = useState(0);
return(
<ul className="filmList">
{movies.map(movie => (
<Film slide={slidePx} key={movie.id} movie={movie} />
))}
</ul>
);
<MainBox/>
의 자식 컴포넌트인 <Film/>
에 slidePx
을 넘겨준다.
//Film.js
const Film = ({ movie, slide }) => {
const { id, name, release_date, image_url } = movie;
return (
<li
className="film"
id={id}
style={{
transform: `translateX(${slide}px)`,
transition: "0.5s ease",
}}
>
props
로 slidePx
을 넘겨 받아 <li>
태그 안에 인라인 스타일링으로
transform : translateX(${slide}px)
을 부여한다.
📌인라인 스타일링을 지양하지만 필요할 때는 사용한다. 사실 절대 사용하면 안되는 것으로 알아서 어떻게든 다른 방법을 선택하려 했지만 필요에 의해서는 당연히 사용해도 된다.
//MainBox.js
<div className="prevBtn">
<i className="fa-solid fa-chevron-left" />
</div>
<div className="nextBtn">
<i className="fa-solid fa-chevron-right" />
</div>
<button>
태그를 사용해도 되지만 SCSS를 편하게 작성하기 위해서 <div>
안에 아이콘을 부여한다.prevBtn
은 이전으로 가는 버튼nextBtn
은 다음으로 가는 버튼🙌버튼이 클릭되면... 그럼 onClick이지!🙌
//MainBox.js
<div className="prevBtn" onClick={toPrev}>
<i className="fa-solid fa-chevron-left" />
</div>
<div className="nextBtn" onClick={toNext}>
<i className="fa-solid fa-chevron-right" />
</div>
💡prevBtn
이 클릭되면 현재 위치에서(slidePx
) +1375px씩 움직인다.
//MainBox.js
const MainBox = ({ movies }) => {
const [slidePx, setSlidePx] = useState(0);
const toPrev = () => {
if (slidePx < 0) setSlidePx(slidePx + 1375);
};
}
📌 slidePx
이 한 번이라도 이동된 상태일 때 즉, slidePx
이 0보다 작을 때
prevBtn
이 클릭되면 slidePx + 1375px
slidePx
이 0일 때는 최초 화면이다. 아무 버튼을 누르지 않았을 때
보통 이전 버튼은 최초화면 일때는 비활성화 되어있다. 지금 보여지는 화면보다 이전의 콘텐츠가 없기 때문이다.
따라서, 이전 버튼은 콘텐츠들이 한 번 넘겨졌을 때 필요하다. 즉, x축으로 최대(음수니깐) - 1375px 움직여야 이전 버튼을 누를 수 있다.
그럼 prevBtn
은 slidePx
이 0보다 작을 때 눌려야 한다. 그렇지 않고 눌리게 되면 아무런 콘텐츠를 보여주지 않는 화면으로 계속 이동한다.
🙌
nextBtn
이 클릭되면 현재 위치에서(slidePx
) -1375px씩 움직인다.🙌
//MainBox.js
const MainBox = ({ movies }) => {
const [slidePx, setSlidePx] = useState(0);
const toNext = () => {
if (slidePx > -2750) setSlidePx(slidePx - 1375);
};
}
반대로 다음에 보여질 콘텐츠가 없다면, 내가 준비한 콘텐츠가 10개라면, nextBtn
이 한 번 클릭되고 더 이상 클릭되면 안된다. 15개라면, 2번....
따라서, 현재 slidePx
값이 -2750px 보다 클때만(음수니깐 -1375px이 -2750px보다 큰 개념) -1375px 만큼 움직이게 조건을 작성한다.
//MainBox.js
const [slidePx, setSlidePx] = useState(0);
const toPrev = () => {
if (slidePx < 0) setSlidePx(slidePx + 1375);
};
const toNext = () => {
if (slidePx > -2750) setSlidePx(slidePx - 1375);
};
//MainBox.js
<div className="prevBtn" onClick={toPrev} style={{ display: slidePx === 0 ? "none" : "" }}>
<i className="fa-solid fa-chevron-left" />
</div>
<div className="nextBtn" onClick={toNext} style={{ display: slidePx === -2750 ? "none" : "" }}>
<i className="fa-solid fa-chevron-right" />
</div>
전설의 인.자.부 무시하기...
인라인 스타일 자제 부탁(동기가 당부한 말)
각 버튼에 style
속성을 부여한다.
삼항 연산자를 사용해서
▶️
prevBtn
slidePx
이 0이라면 즉, 초기화면 이라면 true일 때display: none
false라면display: ""
"block"을 작성하면 css가 삐뚤어짐..그냥 빈 문자열 줘도 됩니다. 어차피 기본 값이 "block"이기 때문이죠
▶️
nextBtn
slidePX
이 -2750이라면 즉, 나의 프로젝트 기준으로 모든 콘텐츠를 보여줬을 때의 px이 2750px이기 때문! 여튼 true일 때display: "none"
false라면display : ""
해당 슬라이드를 React가 아닌 Javascript로 구현한 적이 있다.
처음에는 이걸 어떻게 React로 옮기지...? 심각한데?
그렇게 이틀 동안 구상했다. 썼다 지웠다. 버튼이 활성화 되어야 할 곳에서 비활성화 되고 픽셀이 자꾸 안 맞고...
아주 간단한 로직임에도 한 번 소용돌이 빠지니 작은 오타도 못찾아내는 바보가 되어버린다.
이럴때는 빠져나와 다른 코드를 작성하고 구현해 보다가 다시 돌아오자. 멘토님이 살려주셨다.
막상 작성하니 코딩을 아예 모르는 사람에게 5분안에 설명해도 이해할 정도로 간단한 코드였다.
위의 코드를 리팩토링 해야 하지만 잊어버리기 전에 후딱 작성했다.
완벽히 이해해서 기분이 좋다. 슬라이드가 없는 웹페이지는 거의 없기 때문에 정말 많이 쓰일 것 같다.
지금 다시 보니 Javascript 보다 훨씬 간단하고 쉽게 React로 구현할 수 있었다!!!!
import React, { useState } from "react";
import Film from "./../Film/Film";
import "./MainBox.scss";
const MainBox = ({ movies, theme }) => {
const [slidePx, setSlidePx] = useState(0);
const toPrev = () => {
slidePx < 0 && setSlidePx(slidePx + 1375);
};
const toNext = () => {
slidePx > -4125 && setSlidePx(slidePx - 1375);
};
if (!movies) return;
return (
<div className="mainBox">
<p className="filmTheme">{theme.title}</p>
<ul className="filmList">
{movies.map(movie => (
<Film slide={slidePx} key={movie.id} movie={movie} />
))}
</ul>
<div
className="prevBtn"
onClick={toPrev}
style={{ display: slidePx === 0 ? "none" : "" }}
>
<i className="fa-solid fa-chevron-left" />
</div>
<div
className="nextBtn"
onClick={toNext}
style={{ display: slidePx === -4125 ? "none" : "" }}
>
<i className="fa-solid fa-chevron-right" />
</div>
</div>
);
};
export default MainBox;
잘보고가요!!!