1. 영화 나열을 위한 Row 컴포넌트 생성
이런 식으로 최상단 배너 밑에 영화들이 주제별로 나열될 수 있도록 구현하고자 한다.
Row 컴포넌트를 App.js에 넣어줄 건데, 맨 위에 NEFLIX ORIGINALS는 그 밑에 Trending Now보다 이미지가 크다.
<Row
title="NETFLIX ORIGINALS"
id="NO"
fetchUrl={requests.fetchNetflixOriginals}
isLargeRow
/>
<Row title="Trending Now" id="TN" fetchUrl={requests.fetchTrending} />
<Row title="Top Rated" id="TR" fetchUrl={requests.fetchTopRated} />
<Row
title="Action Movies"
id="AM"
fetchUrl={requests.fetchActionMovies}
/>
<Row
title="Romance Movies"
id="RM"
fetchUrl={requests.fetchRomanceMovies}
/>
이런 식으로 title, id, fetchUrl은 동일하게 하되 NEFLIX ORIGINALS만 isLargeRow를 추가해주었다.
requests 파일에서 오타가 있어서 오전 내내 디버깅 했었던 게 떠오른다. 😇
Row 컴포넌트도 수정한다.
fetchUrl로 받아오는 게 있으니 axios도 import 해야 한다. (단순 axios가 아니라 경로에 있어야 한다.)
위에서 Row에 props로 내려준 것들이 title, id, fetchUrl, isLargeRow라서 그대로 받아준다.
영화 데이터를 저장하기 위해 const [movies, setMovies] = useState([])를 선언해 초기값에 빈 배열을 넣어준다.
useEffect 훅을 사용해 fetchMovieData 라는 콜백 함수를 정해주는데,
이 함수는 비동기 함수로 axios를 써 fetchUrl 에서부터 영화 데이터를 가져온다.
axios.get 메서드가 비동기로 HTTP GET 요청을 보내고 응답을 받아 응답 객체를 반환한다.
await는 이 비동기 작업이 완료될 때까지 대기하는 것이고, 이후 data.results 값을 추출해 setMovies 상태를 업데이트 한다.
import axios from "../api/axios";
import React, { useEffect, useState } from "react";
export default function Row({ isLargeRow, title, id, fetchUrl }) {
const [movies, setMovies] = useState([]);
useEffect(() => {
fetchMovieData();
}, []);
const fetchMovieData = async () => {
const request = await axios.get(fetchUrl);
console.log("request", request);
setMovies(request.data.results);
};
return <div>Row</div>;
}
fetchMovieData 함수를 통해 받아온 request 부분을 콘솔에 찍어보았다.
5개 주제의 영화 각각 20편씩 정보가 담겨 있고, 여기서 data.results 부분이 우리가 원하는 영화들이다. (쭉 나열 시킬 영화 후보들)
이렇게 데이터를 가져왔으면 다음으로 UI를 구성한다.
이 영화별로 타이틀 이름을 보여주고, 쭉 나열된 영화들을 화살표를 클릭해 회전시키고자 한다.
return (
<section className="row">
<h2>{title}</h2> {/* App Row에 있는 title. prop로 받아왔음 */}
<div className="slider">
<div className="slider__arrow-left">
<span
className="arrow"
onClick={() => {
document.getElementById(id).scrollLeft -= window.innerWidth - 80;
}}
>
{"<"}
</span>{" "}
{/* 그냥 <>만 쓰면 태그인줄 알고 오류 발생 */}
</div>
// 이 사이에 영화 들어갈 것임
<div className="slider__arrow-right">
<span
className="arrow"
onClick={() => {
document.getElementById(id).scrollLeft += window.innerWidth - 80;
}}
>
{">"}
</span>
</div>
</div>
</section>
);
}
section으로 구성하는데 영화 타이틀 / 화살표 왼쪽 / 영화 포스터 / 화살표 오른쪽 이런 식이다.
위 코드에는 영화 포스터 부분이 생략되어 있다.
왼쪽 화살표{"<"}를 누르면 document.getElementById(id) 의 가로 스크롤 위치를 왼쪽으로 이동 시킨다.
현재 창 너비에서 80씩 뺀 만큼 왼쪽으로 이동 시키는 것이다. 오른쪽의 경우에는 80씩 더해주는 것으로 오른쪽으로 이동을 시킨다.
여기서 id는 아까 위에서 Row 컴포넌트에 id를 받았는데, 각 영화 별로 가진 id를 말한다.
그래서 클릭하면 그 id 값을 찾아 스크롤 위치를 바꿔주는 것으로 이해했다.
📌 scrollLeft : 요소의 가로 스크롤 위치를 나타내는 속성
📌 window.innerWidth : 현재 창 너비
<div id={id} className="row__posters">
{movies.map((movie) => (
<img
key={movie.id}
className={`row__poster ${isLargeRow && "row__posterLarge"}`}
src={`https://image.tmdb.org/t/p/original/${
isLargeRow ? movie.poster_path : movie.backdrop_path
}`}
alt={movie.name}
/>
))}
</div>
사이에 들어갈 영화 부분이다. map 메서드로 배열 movies를 순회하면서 각각의 영화 데이터를 꺼내준다.
꺼낼 때 이미지 파일로 꺼내는데, 이미지를 나열하기 때문에 key 값을 주어야 한다. 이는 각 영화가 가진 id 값을 부여한다.
안 그러면 리액트에서 경고 메세지를 주는데 이는 목록을 랜더링 할 때 각 요소에 고유한 식별자가 있어야 변경 사항을 인지하기 때문이다.
아까 위에서 쓴 id가 아니라, 받아온 데이터 안에도 id 값이 있다. 그걸 꺼낸 것이다.
className의 경우 row__poster는 기본으로 설정되는데, isLargeRow가 true라면 row__posterLarge가 추가되는 것이다.
아까 넷플릭스 오리지널 콘텐츠는 포스터가 더 크기 때문이 이러한 값을 줬었다. 이 여부에 따라 CSS를 따로 추가해준다.
src는 이 글 시리즈 처음에 영화 이미지를 받아오는 주소를 적어두었다.
그 주소대로 가되 큰 포스터는 movie.poster_path 고, 작은 포스터는 movie.backdrop_path에 있어서 삼항연산으로 달리 해준다.
이런 식으로 영화 이미지를 받아오고 CSS 작업을 한다.
강사님이 CSS를 다 주셨는데 모르는 부분들이 있어 정리했다.
📌 background-clip: content-box
배경 이미지나 배경 색상이 콘텐츠 상자 안에서만 표시되도록 한다.
background-clip - CSS: Cascading Style Sheets | MDN
CSS background-clip 속성은 요소의 배경이 테두리, 안쪽 여백, 콘텐츠 상자 중 어디까지 차지할 지 지정합니다.
developer.mozilla.org
📌 z-index
해당 요소의 쌓임 순서를 지정한다. 값이 클수록 위에 올라온다. 값이 작으면 값이 더 높은 요소들에게 깔리게 된다.
z-index - CSS: Cascading Style Sheets | MDN
CSS z-index 속성은 위치 지정 요소와, 그 자손 또는 하위 플렉스 아이템의 Z축 순서를 지정합니다. 더 큰 z-index 값을 가진 요소가 작은 값의 요소 위를 덮습니다.
developer.mozilla.org
📌 visibility
해당 요소를 숨기고 공간도 제거할 수 있다.
1. visible: 요소가 보인다.
2. hidden: 요소를 숨긴다. 그러나 요소가 차지하는 공간은 유지된다.
3. collapse: 요소를 숨긴다. 요소가 차지한 공간도 제거한다. 테이블 요소(<table>, <tr>, <td>에 사용되며 행, 열을 숨길 때 쓴다.)
hidden이랑 display:none이랑 비슷해보이는데, display의 경우 요소도 숨기고 공간도 차지하지 않는다.
더불어 none은 요소가 렌더링되지 않아 DOM에 존재하지 않지만, visibility:hidden은 렌더링되어 DOM에 존재한다는 차이가 있다.
visibility - CSS: Cascading Style Sheets | MDN
visibility CSS 속성은 문서의 레이아웃을 변경하지 않고 요소를 보이거나 숨깁니다. visibility로 <table>의 행이나 열을 숨길 수도 있습니다.
developer.mozilla.org
📌 overflow
요소의 콘텐츠가 너무 커서 블록 서식에 맞출 수 없을 때 어떻게 처리하는지 설정한다.
1. visible: 블록 밖으로 삐져 나온다.
2. hidden: 블록 밖으로 보이지 않는다. 스크롤바나 드래그할 순 없지만 코드를 사용해서 스크롤 할 수는 있다!
3. clip: 블록 밖으로 보이지 않는다. 위와 달리 이미 잘린 거라서 스크롤도 되지 않는다.
4. scroll: 블록 안으로 보이되 스크롤바로 나머지 콘텐츠를 볼 수 있다.
5. auto: 콘텐츠가 크기를 초과하면 스크롤바를 자동으로 추가한다.
overflow - CSS: Cascading Style Sheets | MDN
overflow CSS 단축 속성은 요소의 콘텐츠가 너무 커서 요소의 블록 서식 맥락에 맞출 수 없을 때의 처리법을 지정합니다. overflow-x (en-US), overflow-y (en-US)의 값을 설정합니다.
developer.mozilla.org
쭉 나열된 영화 포스터에서 썼는데, overflow-y에 hidden을 써서 수직 스크롤바를 숨기고, overflow-x에서 scroll을 써 수평 스크롤을 가능케 했다.
📌 scroll-behavior
스크롤에 애니메이션 효과를 적용하는데, smooth 값을 설정해서 스크롤이 부드럽게 이동하도록 했다.
scroll-behavior - CSS: Cascading Style Sheets | MDN
The scroll-behavior CSS property sets the behavior for a scrolling box when scrolling is triggered by the navigation or CSSOM scrolling APIs.
developer.mozilla.org
📌 object-fit
<img> <video> 같은 요소들의 콘텐츠 크기를 조절한다.
1. fill: 콘텐츠가 늘어나든 말든 요소 콘텐츠 박스에 맞춘다.
2. contain: 대체 콘텐츠(부모 요소)의 가로세로 비율을 유지하면서 들어간다. 상하좌우에 여백이 생길 수 있다.
3. cover: 가로세로 비율을 유지하면서 콘텐츠 박스를 채운다. 딱 맞지 않으면 일부가 잘려 나간다.
4. none: 크기를 조절하지 않는다.
5. scale-down: none과 contain 중에 대체 콘텐츠의 크기가 더 작아지는 값을 고른다.
object-fit - CSS: Cascading Style Sheets | MDN
CSS object-fit 속성은 <img>나 <video> 요소와 같은 대체 요소의 콘텐츠 크기를 어떤 방식으로 조절해 요소에 맞출 것인지 지정합니다.
developer.mozilla.org
2. Footer 만들기
웹페이지 하단에 저작권이나 고객센터 같은 정보가 나열된 부분이 있는데 거기를 만들어 볼 것이다.
App.js에 Footer 컴포넌트도 추가해주고, Footer 컴포넌트의 디자인은 styled components로 진행했다.
-----풋터 컨테이너-----
----풋터 콘텐츠----
---링크 컨테이너---
이렇게 위아래를 만들어주고 그 안에 title, link, descRights 를 태그에 감싸서 넣어준다.
styled components에서는 &를 쓰는데 이게 현재 디자인하고 있는 컴포넌트를 의미한다고 한다.
const FooterLink = styled.a`
color: gray;
font-size: 14px;
width: 110px;
margin-bottom: 21px;
&:hover {
text-decoration: underline;
}
@media (max-width: 768px) {
margin-bottom: 16px;
}
`;
이런 식으로 쓴다. 그래서 FooterLink에 hover 했을 때 밑줄이 그어지게 하는 효과를 넣었다.
완성된 Footer 부분은 아래와 같다.
호버 안 했는데 왜 밑줄이 쳐져 있지... ㅎㅎ
'⚛️ React > 💭 따라하며 배우는 React A-Z' 카테고리의 다른 글
[React] React-Router-DOM과 API에 대해 알아보자 (feat. 따라하며 배우는 리액트 A-Z) (0) | 2023.06.02 |
---|---|
[React] 넷플릭스 웹페이지의 모달을 구현해보자 (feat. 따라하며 배우는 리액트 A-Z) (0) | 2023.06.02 |
[React] 넷플릭스 웹페이지의 배너를 클론해보자 (feat. 따라하며 배우는 리액트 A-Z) (0) | 2023.05.30 |
[React] Hooks / TailWindCSS / 라이브러리를 활용해 메모 앱을 업그레이드 해보자 (feat. 따라하며 배우는 리액트 A-Z) (0) | 2023.05.25 |
[React] 리액트로 to do 앱을 만들어보자 (feat. 따라하며 배우는 리액트 A-Z) (0) | 2023.05.24 |