🐨CoalaCoding
DocsExamplesTry itBoardB반
🐨CoalaCoding

개발자를 위한 한국어 웹 기술 문서

문서

  • JavaScript
  • Web Publishing
  • React
  • Python

커뮤니티

  • 게시판
  • 예제 모음
  • Try it 에디터

기타

  • GitHub
  • 관리자
© 2026 CoalaCoding. All rights reserved.
  • 22_무비앱-완료본
  • 01. GOFLIX 프로젝트 소개와 개발환경 설정
  • 02. React 진입점과 라우팅 설정
  • 03. Axios로 TMDB API 연결하기
  • 04. 공통 UI 컴포넌트 만들기 (UI.jsx)
  • 05. App.jsx — 레이아웃 구성과 데이터 가져오기
  • 06. Header와 Footer 만들기
  • 07. Home.jsx — 메인 페이지 완성하기
  • 08. Section과 Card — 영화 카드 목록 만들기
  • 09. MovieDetail — 영화 상세 페이지 만들기
  • 10. Category, ErrorPage 완성하기
  • 11. AI 챗봇 연동하기
  • 12_Swiper_캐러셀_적용과_프로젝트_마무리
  • 13. GOFLEX Gemini CLI 바이브코딩 프롬프트 템플릿
  • 00_시작하기
  • 01_App
  • 02_CSS
  • 03_Nav
  • 04_Hero
  • 05_AboutMe
  • 06_Projects
  • 07_Contact
  • 08_Footer
  • 09_완성_정리
  • 10_바이브코딩
  1. 홈
  2. 문서
  3. React
  4. 실전 프로젝트
  5. 07. Home.jsx — 메인 페이지 완성하기

07. Home.jsx — 메인 페이지 완성하기

히어로 영상, 인기영화 하이라이트, 영화 목록 섹션으로 메인 화면을 만든다

코드 블록의 Try it Yourself 버튼으로 직접 실행할 수 있다.

구문

💡TIP

Gemini CLI로 구현하기 — Home 메인 페이지

  • 프롬프트: gemini "src/components/Home.jsx를 작성해줘. useOutletContext로 now, popular, topRated, loading 데이터를 받아야 해. 상단에는 배경 영상([영상 파일명])과 인기영화 첫 번째 항목을 히어로로 표시하고, 하단에는 현재 상영작/인기 영화/최고 평점 3개의 Section 컴포넌트를 보여줘. 로딩 중에는 Spinner를 표시해줘."
    • 사용 가이드: [영상 파일명]을 public 폴더에 넣은 동영상 파일 이름으로 바꾼다(예: video.mp4).

1. Home 페이지의 구조

GOFLEX의 메인 페이지는 두 가지 영역으로 나뉜다.

  • 히어로(Hero) 영역 — 배경 영상 + 인기 영화 하이라이트 + "자세히 보기" 버튼
  • 영화 목록 영역 — 현재 상영작, 인기 영화, 최고 평점 3개 섹션
순서만들 기능핵심 개념
1단계import + 데이터 받기useOutletContext
2단계히어로 영역비디오 배경, 조건부 렌더링
3단계영화 목록 영역Section 재사용, loading 처리

2. 1단계 — import + 데이터 받기

src/components/Home.jsx 파일을 열고 임시 코드를 모두 지운 뒤 아래를 작성한다.

import { useOutletContext, Link } from "react-router";
import { Section } from "./Section.jsx";
import { Spinner } from "./UI.jsx";

export function Home() {
  const { now, popular, topRated, loading } = useOutletContext();

  // 인기영화 첫 번째를 히어로에 표시
  const hero = popular.length > 0 ? popular[0] : null;
줄설명
1useOutletContext(유즈아울렛컨텍스트)로 5편에서 App.jsx가 Outlet의 context prop으로 전달한 데이터를 받는다. Link는 히어로의 "자세히 보기" 버튼에 사용한다.
34편에서 만든 Spinner 컴포넌트를 가져온다. 데이터가 아직 도착하지 않았을 때 "불러오는 중..." 메시지를 표시한다.
6객체 구조 분해(Destructuring, 디스트럭처링) — 객체에서 필요한 프로퍼티를 개별 변수로 추출하는 문법이다. useOutletContext()가 반환한 객체에서 now, popular, topRated, loading을 각각 변수로 꺼낸다.
8삼항 연산자(조건 ? 참 : 거짓)이다. popular 배열에 요소가 있으면 첫 번째 요소(popular[0])를 hero에 저장하고, 없으면 null을 저장한다.

3. 2단계 — 히어로 영역

같은 Home.jsx 파일에서, 1단계의 hero 변수 선언 바로 아래에 return을 작성한다. 히어로 영역은 세 겹의 레이어(배경 영상 → 오버레이 → 텍스트)로 구성된다. position: absolute 요소를 겹쳐서 레이어를 구성하는 CSS 포지셔닝 기법이다.

  return (
    <>
      <section className="relative h-screen overflow-hidden">
        <video src="video.mp4" className="absolute top-0 left-0 w-full h-full object-cover" autoPlay muted loop playsInline />
        <div className="absolute bg-black/50 w-full h-full top-0 left-0"></div>
    {/* 다음탭으로 */}
줄설명
3relative — CSS position: relative이다. 자식 요소 중 position: absolute인 요소의 기준 컨테이너가 된다. h-screen은 뷰포트 전체 높이를 차지한다. overflow-hidden은 자식 요소가 영역을 벗어나면 잘라낸다.
4absolute top-0 left-0 — CSS position: absolute이다. 가장 가까운 relative 부모를 기준으로 좌상단에 위치한다. object-cover는 가로세로 비율을 유지하면서 컨테이너를 꽉 채운다. autoPlay muted loop playsInline은 자동 재생, 음소거, 반복, 모바일 인라인 재생 속성이다.
5bg-black/50 — 50% 투명한 검정 막을 영상 위에 덮는다. 글자가 잘 보이도록 배경을 어둡게 만든다.

4. 3단계 — 영화 목록 영역

같은 Home.jsx 파일에서, 히어로 </section> 태그 바로 아래에 이어서 작성한다. loading 상태에 따라 스피너 또는 영화 목록을 조건부 렌더링한다.

      {loading && <Spinner className="text-center py-20 bg-black" />}

      {!loading && (
        <>
          <Section title="현재 상영작" items={now} category="now_playing" />
          <Section title="인기 영화" items={popular} category="popular" />
          <Section title="최고 평점" items={topRated} category="top_rated" />
        </>
      )}
    </>
  );
}
줄설명
1loading이 true이면 Spinner 컴포넌트로 "불러오는 중..." 텍스트를 표시한다.
3-8!(NOT 연산자)는 불린 값을 반전시킨다. loading이 true이면 !loading은 false, loading이 false이면 !loading은 true가 된다. 로딩이 끝났을 때(false) 3개의 Section을 표시한다. category prop은 "더보기" 링크에 사용된다.
5category="now_playing"은 Section에서 /category/now_playing 링크를 생성한다.

5. 동작 확인

확인 항목기대 결과
히어로 영역배경 영상 위에 "GOFLEX" + 인기 영화 제목 + "자세히 보기" 버튼
"자세히 보기" 클릭해당 영화 상세 페이지로 이동
스크롤 아래"현재 상영작", "인기 영화", "최고 평점" 섹션 표시
⚠️WARNING

아직 Section과 Card 컴포넌트를 만들지 않았으므로 에러가 발생할 수 있다. 바로 다음 편에서 만든다.


6. 전체 코드

import { useOutletContext, Link } from "react-router";
import { Section } from "./Section.jsx";
import { Spinner } from "./UI.jsx";

export function Home() {
  const { now, popular, topRated, loading } = useOutletContext();

  // 인기영화 첫 번째를 히어로에 표시
  const hero = popular.length > 0 ? popular[0] : null;

  return (
    <>
      {/* 상단 비디오 영역 */}
      <section className="relative h-screen overflow-hidden">
        <video src="video.mp4" className="absolute top-0 left-0 w-full h-full object-cover" autoPlay muted loop playsInline />
        <div className="absolute bg-black/50 w-full h-full top-0 left-0"></div>
        <div className="relative container mx-auto flex flex-col justify-center items-center h-full text-center px-6">
          <h2 className="text-5xl md:text-7xl lg:text-9xl font-bold text-yellow-400">GOFLEX</h2>
          <p className="text-xl md:text-2xl text-white mt-4">최신 영화와 인기 작품을 만나보세요.</p>
          {hero && (
            <div className="mt-8 flex flex-col items-center gap-3">
              <p className="text-gray-300 text-lg">지금 인기 있는 영화</p>
              <h3 className="text-3xl md:text-4xl font-bold text-white">{hero.title}</h3>
              <Link to={`/movie/${hero.id}`} className="mt-2 bg-yellow-400 text-black px-8 py-3 rounded-lg font-bold hover:bg-yellow-300 transition-colors">
                자세히 보기
              </Link>
            </div>
          )}
        </div>
      </section>

      {/* 영화 목록 */}
      {loading && <Spinner className="text-center py-20 bg-black" />}

      {!loading && (
        <>
          <Section title="현재 상영작" items={now} category="now_playing" />
          <Section title="인기 TV" items={popular} category="popular" />
          <Section title="최고 평점" items={topRated} category="top_rated" />
        </>
      )}
    </>
  );
}

목차

  • 구문