React

 

따라하며 배우는 리액트 A-Z

 


[프론트엔드, 웹 개발] 강의입니다.

이 강의를 통해 리액트 기초부터 중급까지 배우게 됩니다. 하나의 강의로 개념도 익히고 실습도 하며, 리액트를 위해 필요한 대부분의 지식을 한번에 습득할 수 있도록 만들었습니다.

✍️
이런 걸
배워요!

리액트

NextJS

타입스크립트

정적 사이트 자동 배포

도커

 

강의:  https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8#

 

강의 자료 :  https://github.com/braverokmc79/DiagramPDF

 

소스:  https://github.dev/braverokmc79/react-netflix-clone

 

 

 

 

 

[4]. Netflix 앱 만들기 시작

 

 

32.만들게 될 Netfilx 애플리케이션 소개

 

강의:

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119874?tab=curriculum

 

 

 

 

 

 

 

 

 

 

 

 

33.Create-React-App으로 리액트 설치하기

 

강의 :

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119875?tab=curriculum

 

 

 

 

 

 

 

 

 

35.The Movie DB API Key 생성하기

강의 :

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119876?tab=curriculum

 

 

https://www.themoviedb.org/

 

https://www.themoviedb.org/documentation/api

 

API Key 가져오기

https://www.themoviedb.org/settings/api

 

 

 

 

 

 

 

 


Get Movie BY Latest
https://api.themoviedb.org/3/movie/latest?api_key=<<api_key>>&language=ko-KR

 

Get Movie Detail
https://api.themoviedb.org/3/movie/{movie_id}?api_key=<<api_key>>&language=ko-KR

 

Get Movie Reviews
https://api.themoviedb.org/3/movie/{movie_id}/reviews?api_key=<<api_key>>&language=ko-KR&page=1

 

Get Trending
https://api.themoviedb.org/3/movie/latest?api_key=<<api_key>>&language=ko-KR

 

 

https://api.themoviedb.org/3/

 

 

https://image.tmdb.org/t/p/original/wwemzKWzjKYJFfCeiB57q3r4Bcm.svg
 

https://image.tmdb.org/t/p/original/wwemzKWzjKYJFfCeiB57q3r4Bcm.png
 

https://image.tmdb.org/t/p/w500/wwemzKWzjKYJFfCeiB57q3r4Bcm.png

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

36.The Movie DB API 요청을 위한 Axios 인스턴스 생성 및 요청 보내기

 

강의 : 

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119877?tab=curriculum

 

 

npm i axios 

 

 

 

 

 


Get Movie BY Latest
https://api.themoviedb.org/3/movie/latest?api_key=<<api_key>>&language=ko-KR

 

Get Movie Detail
https://api.themoviedb.org/3/movie/{movie_id}?api_key=<<api_key>>&language=ko-KR

 

Get Movie Reviews
https://api.themoviedb.org/3/movie/{movie_id}/reviews?api_key=<<api_key>>&language=en-US&page=1

 

Get Trending
https://api.themoviedb.org/3/movie/latest?api_key=<<api_key>>&language=ko-KR

 

 

 

src/api/axios.js

import axios from 'axios';

const instance = axios.create({

    baseURL: "https://api.themoviedb.org/3/",
    params: {
        api_key: "08d90cc4e7968b1f8e51588a0d42cf06",
        language: "ko-KR",
    }

});

export default instance;

 

 

src/api/requests.js

const requests = {
    fetchNowPlaying: "movie/now_playing",
    fetchNetflixOriginals: "/discover/tv?with_networks=213",
    fetchTrending: "/trending/all/week",
    fetchTopRated: "/movie/top_rated",
    fetchActionMovies: "/discover/movie?with_genres=28",
    fetchComedyMovies: "/discover/movie?with_genres=35",
    fetchHorrorMovies: "/discover/movie?with_genres=27",
    fetchRomanceMovies: "/discover/movie?with_genres=10749",
    fetchDocumentaries: "/discover/movie?with_genres=99",
}

export default requests;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

37.넷플릭스 애플리케이션 전체 구조 생성하기

 

강의 : 

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119878?tab=curriculum

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

39.네비게이션 바 컴포넌트 생성하기

 

강의 : 

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119879?tab=curriculum

 

 

 

 

 

 

 

 

 

 

 

 

 

 

40.이미지 배너 생성하기

강의 :

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119880?tab=curriculum

 

 

 

api/components/Nav.js

import React, { useEffect, useState } from 'react';
import './Nav.css';

const Nav = () => {
    const [show, setShow] = useState(false);

    useEffect(() => {
        window.addEventListener("scroll", () => {
            console.log("scrollY :", window.scrollY)
            if (window.scrollY > 50) {
                setShow(true);
            } else {
                setShow(false);
            }
        });
        return () => {
            window.removeEventListener("scroll", () => { });
        }
    }, []);



    return (
        <nav className={`nav ${show && "nav__black"}`}>
            <img
                alt="Netflix logo"
                src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Netflix_2015_logo.svg/170px-Netflix_2015_logo.svg.png"
                className='nav__logo'
                onClick={() => window.location.reload()}
            />

            <img
                alt='User logged'
                src="https://occ-0-4796-988.1.nflxso.net/dnm/api/v6/K6hjPJd6cR6FpVELC5Pd6ovHRSk/AAAABbme8JMz4rEKFJhtzpOKWFJ_6qX-0y5wwWyYvBhWS0VKFLa289dZ5zvRBggmFVWVPL2AAYE8xevD4jjLZjWumNo.png?r=a41"
                className='nav__avatar'
            />

        </nav>
    );
};

export default Nav;

 

 

api/components/Nav.css

.nav{
    position: fixed;
    top:0;
    width: 100%;
    height: 30px;
    z-index: 1;
    padding: 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    transition-timing-function: ease-in;
    transition: all 0.5s;
    
}
.nav__black{
    background-color: #111;
}
.nav__logo{
    position: fixed;
    left: 40px;
    width: 80px;
    object-fit: contain;
}

.nav__avatar{
    position: fixed;
    right:40px;
    width:30px;
    object-fit: contain;
}

 

 

 

 

 

 

 

 

 

 

 

 

41.이미지 배너 생성하기

강의:

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119880?tab=curriculum

 

src/components/Banner.js

import React, { useState, useEffect } from 'react';
import axios from '../api/axios';
import requests from '../api/requests';
import './Banner.css';

const Banner = () => {
    const [movie, setMovie] = useState([]);

    useEffect(() => {
        fetchData();
    }, []);

    const fetchData = async () => {

        //현재 상영중인 영화 정보를 가져오기(여러 영화)
        const request = await axios.get(requests.fetchNowPlaying);

        //여러 영화 중 영화 하나의 ID 를 가져오기
        const movieId =
            request.data.results[Math.floor(Math.random() * request.data.results.length)].id;

        //특정 영화의 더 상세한 정보를 가져오기 (비디오 정보도 포함)
        const { data: movieDetail } = await axios.get(`/movie/${movieId}`,
            {
                params: { append_to_response: "videos" }
            }
        );

        setTimeout(() => {
            setMovie(movieDetail);
        }, 100);

        console.log("movie3  : ", movie);

    };

    const truncate = (str, n) => {
        return str?.length > n ? str.substr(0, n - 1) + "..." : str;
    }

    return (
        <header
            className="banner"
            style={{
                backgroundImage: `url("https://image.tmdb.org/t/p/original/${movie.backdrop_path}")`,
                backgroundPosition: "top center",
                backgroundSize: "cover",
            }}
        >
            <div className="banner__contents">
                <h1 className="banner__title">
                    {movie.title || movie.name || movie.original_name}
                </h1>

                <div className="banner__buttons">
                    <button className="banner__button play">
                        Play
                    </button>
                    <button className="banner__button info">More Information</button>
                </div>

                <h1 className="banner__description">
                    {truncate(movie.overview, 100)}
                </h1>
            </div>
            <div className="banner--fadeBottom" />
        </header>
    );
};

export default Banner;

 

 

 

src/components/Banner.css

.banner {
  color: white;
  object-fit: contain;
  height: 448px;
}

.banner__contents {
  margin-left: 40px;
  padding-top: 140px;
  height: 190px;
}
.banner__title {
  font-size: 3rem;
  font-weight: 800;
  padding-bottom: 0.5rem;
}
.banner__description {
  width: 45rem;
  line-height: 1.3;
  padding-top: 1rem;
  font-weight: 500;
  font-size: 1rem;
  max-width: 400px;
  height: 80px;
}
.banner--fadeBottom {
  height: 7.4rem;
  background-image: linear-gradient(
    180deg,
    transparent,
    rgba(37, 37, 37, 0.61),
    #111
  );
}
.banner__buttons {
  display: flex;
  flex-direction: row;
}
.banner__button {
  display: flex;
  flex-direction: row;
  justify-content: start;
  align-items: center;
  cursor: pointer;
  outline: none;
  border: none;
  font-size: 1rem;
  font-weight: 700;
  border-radius: 0.2vw;
  padding: 0.4rem 1.8rem 0.4rem 1rem;
  margin-right: 1rem;
}
.banner__button:hover {
  color: #000;
  background-color: rgba(170, 170, 170, 0.9);
  transition: all 0.2s;
}
.play {
  background-color: white;
  color: black;
}
.info {
  background-color: rgba(109, 109, 110, 0.7);
  color: white;
}
.info:hover {
  background-color: rgb(74, 74, 74);
  color: white;
}

.space {
  margin-left: 4px;
}


@media (min-width: 1500px) {
  .banner {
    position: relative;
    height: 600px;
  }
  .banner--fadeBottom {
    position: absolute;
    bottom: 0;
    width: 100%;
    height: 40rem;
  }
}
@media (max-width: 768px) {
  .banner__contents {
    width: min-content !important;
    padding-left: 2.3rem;
    margin-left: 0px !important;
  }
  .banner__description {
    font-size: 0.8rem !important;
    width: auto !important;
  }
  .info {
    text-align: start;
    padding-right: 1.2rem;
  }
  .space {
    margin-left: 6px;
  }
  .banner__button {
    font-size: 0.8rem !important;
    border-radius: 4px !important;
  }
}

@media (max-width: 560px) {
  .banner__contents {
    width: 80% !important;
    padding-left: 2.3rem;
    margin-left: 0px !important;
    padding-top: 40px;
  }
  .banner__description {
    font-size: 0.8rem !important;
    width: auto !important;
  }
  .info {
    text-align: start;
    padding-right: 1.2rem;
  }
  .space {
    margin-left: 6px;
  }
  .banner__buttons{
    justify-content: space-evenly;
  }
  .banner__button {
    font-size: 0.8rem !important;
    border-radius: 4px !important;
   
  }


  .banner--fadeBottom {
    padding-bottom: 70px !important;
 }

}

 

 

 

 

 

 

 

 

 

 

 

 

42.Styled Component에 대해서

 

강의:

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119881?tab=curriculum

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

43.Styled Component를 이용한 비디오 배너 생성하기

강의 :

https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8/unit/119882?tab=curriculum

 

 

 

 

 

src/components/Banner.js

import React, { useState, useEffect } from 'react';
import axios from '../api/axios';
import axiosEn from '../api/axiosEn';
import requests from '../api/requests';
import './Banner.css';
import styled from 'styled-components';

const Container = styled.div`
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    width: 100%;
    height: 100vh;
    background:black;
`;

const HomeContainer = styled.div`
    width: 100%;
    height: 100%;
   
`;

const Iframe = styled.iframe`
    width: 100%;
    height: 100%;
    z-index: -1;
    opacity: 0.65;
    border: none;

    &::after{
       content:"" ;
       position: absolute;
       top: 0;
       left: 0;
       width: 100%;
       height: 100%;       
    }
`;

const Banner = () => {
    const [movie, setMovie] = useState([]);
    const [movieKey, setMovieKey] = useState("");
    const [isClicked, setIsClicked] = useState(false);

    useEffect(() => {
        fetchData();
    }, []);

    const fetchData = async () => {

        //현재 상영중인 영화 정보를 가져오기(여러 영화)
        const request = await axios.get(requests.fetchNowPlaying);

        const results = request.data.results.filter(data => {
            return data.overview.length > 1
        })

        console.log(" results", results);

        //여러 영화 중 영화 하나의 ID 를 가져오기
        const movieId = results[Math.floor(Math.random() * results.length)].id;

        //특정 영화의 더 상세한 정보를 가져오기 (비디오 정보도 포함)
        const { data: movieDetail } = await axios.get(`movie/${movieId}`, {
            params: { append_to_response: "videos" },
        });

        setMovie(movieDetail);


        //비디오가 없다면 다음을 실행
        if (movie.videos === undefined) {
            const { data: movieDetailEn } = await axiosEn.get(`movie/${movieId}`, {
                params: { append_to_response: "videos" },
            });
            setMovieKey(movieDetailEn.videos.results[0].key);
        } else {
            setMovieKey(movie.videos.results[0].key)
        }

    };

    const truncate = (str, n) => {
        return str?.length > n ? str.substr(0, n - 1) + "..." : str;
    }



    if (!isClicked) {
        return (
            movie.backdrop_path && <header
                className="banner"
                style={{
                    backgroundImage: `url("https://image.tmdb.org/t/p/original/${movie.backdrop_path}")`,
                    backgroundPosition: "top center",
                    backgroundSize: "cover",
                }}
            >
                <div className="banner__contents">
                    <h1 className="banner__title">
                        {movie.title || movie.name || movie.original_name}
                    </h1>

                    <div className="banner__buttons">
                        <button className="banner__button play" onClick={() => setIsClicked(true)}>
                            Play
                        </button>

                        <button className="banner__button info">More Information</button>
                    </div>

                    <h1 className="banner__description">
                        {truncate(movie.overview, 100)}
                    </h1>
                </div>
                <div className="banner--fadeBottom" />
            </header>
        );

    } else {


        return (
            <Container >
                <HomeContainer>
                    <Iframe
                        width="640"
                        height="360"
                        src={`https://www.youtube.com/embed/${movieKey}?controls=0&autoplay=1&loop=1&mute=1&playlist=${movieKey}`}
                        title="YouTube video player"
                        frameborder="0"
                        allow="autoplay; fullscreen"
                        allowfullscreen
                    ></Iframe>
                </HomeContainer>

            </Container >

        );
    }
};

export default Banner;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

react

 

about author

PHRASE

Level 60  라이트

다른 사람을 탓하고 원망하는 사람은 아무 것도 이룰 수 없다. -앤드류 매튜스

댓글 ( 4)

댓글 남기기

작성