동영상 스트리밍 서비스를 제공하는 YouTube 사이트를 기획과 디자인을 제외하고 주요 기능만을 구현한 clone 프로젝트입니다. youtube의 API를 활용하여 영상 스트리밍 페이지의 기능을 구현했습니다.
- 2021.01.18 ~ 2021.02.01
- ReactJS / React-Hooks / PostCss
- Axios 라이브러리
- JavaScript(ES6) / HTML
- Notion (프로젝트 기능 구현 계획과 일정 관리)
- Git + GitHub
- Postman (API data 관리)
src
├── components
│ ├── nav
│ │ ├── nav.jsx
│ │ └── nav.module.css
│ ├── videoDetail
│ │ ├── videoDetail.jsx
│ │ └── videoDetail.module.css
│ ├── videoItem
│ │ ├── videoItem.jsx
│ │ └── videoItem.module.css
│ └── videoList
│ ├── videoList.jsx
│ └── videoList.module.css
├── index.css
├── index.js
├── pages
│ ├── main.jsx
│ └── main.module.css
├── service
│ ├── youtube-fetch.js
│ └── youtube.js
└── styles
└── reset.css
- 기존의 디자인을 바탕으로 Component 설계
- PostCSS를 이용한 효율적인 웹 디자인 구현
- Youtube API와 Map method를 이용한 data render
- 검색 결과에 따른 data render 기능 구현
- Axios 라이브러리와 Dependency Injection을 통한 효율적인 API 관리
- 각각의 component에 따른 Modal 구현
- 반응형 웹페이지 구현
Most Popular Videos API와 Map method를 이용한 자동 Data render
- 현재 Youtube에서 스트리밍 되는 영상 중 사용자들이 가장 많이 보는 영상을 확인할 수 있는 메인 페이지입니다.
- Youtube 서비스 API 만 받아오는
class
를 만들어서,mostPopular
함수로mostPopular
API를 담아 관리하였고,useEffect
함수를 사용하여 해당 youtube API를 받아올 때마다 자동으로 렌더될 수 있도록 하였습니다.
검색 결과에 따른 Search Videos API data render 기능 구현
- 현재 Youtube에서 스트리밍 되는 영상 중 검색에 따라 해당하는 결과를 확인할 수 있는 검색 페이지입니다.
- Youtube 서비스 API 만 받아오는
class
를 만들어서,search
함수로 search video API를 담아 관리하였습니다. - input 창에서 검색어를 입력한 뒤 엔터를 치면,
useRef
로 연결한input
에서value
값을 받아온 뒤, 해당 검색 서비스인search
함수에서 검색어(value
) 값을 쿼리 인자로 받아 완성된 API로 결과 페이지를 렌더하도록 하였습니다. - 검색 기능이 실행되면, 해당
input
의value
값은 빈 값(""
)으로 초기화됩니다.
- 영상을 클릭하면 모달로 영상의 상세 페이지를 확인할 수 있습니다.
- 조건식과 이벤트 함수를 통해서 상위 컴포넌트에서
props
로 받아온video
와id
값을 이용한 modal이 구현됩니다. - 모달의
x
버튼을 누르거나, 배경을 클릭하면onClick
이벤트 함수로state
가 변경되어 모달창이 사라집니다.
- @media screen 을 이용하여 반응형 사이트를 구현했습니다.
Axios 라이브러리 와 Dependency Injection을 통한 API 보안 관리
- 팀 프로젝트를 진행했을 때에는 백엔드에서 관리를 해주고, 프론트에서 받아오는 방식으로 사용했었으나, 직접 API를 받고 배포까지 진행해야 했기 때문에 간단하게나마 Axios 라이브러리를 사용하고 Dependency Injection 을 통해 보안과 가독성을 염두에둔 효율적인 API 관리가 필요했습니다. 이를 위해서 Dependency Injection 방식을 차용하였습니다.
- 최상위에서 .env(환경파일)을 만든 뒤에 API KEY 를 담아 변수 선언 해주고 가장 최상위 파일인 index.js에 axios.create 명령어를 사용하여 params의 오브젝트 key를 process.env.REACT_APP_YOUTUBE_API_KEY 로 값을 설정해주었습니다.
import React from "react";
import ReactDOM from "react-dom";
import Main from "./pages/main";
import Youtube from "./service/youtube";
import axios from "axios";
import "./index.css";
const httpClient = axios.create({
baseURL: "https://youtube.googleapis.com/youtube/v3",
params: { key: process.env.REACT_APP_YOUTUBE_API_KEY },
});
const youtube = new Youtube(httpClient);
ReactDOM.render(
<React.StrictMode>
<Main youtube={youtube} />
</React.StrictMode>,
document.getElementById("root")
);
- Youtube 서비스 통신 API 만 받아오는 class js 파일을 만든 후, 서비스 기능에 맞는 함수에 각각 API를 담아 관리하였고, 해당 API가 필요한 컴포넌트에서 해당 함수를 받아오는 방식으로 구현하였습니다.
- index.js로부터 전달받은 httpClient을 할당해주었고 각 데이터를 받아올 때 사용해주었습니다. 코드의 가독성을 높이기 위해서 각각의 데이터 조건에 해당하는 값들은 get으로 받아온 뒤 params 안에서 정리해주었습니다.
class Youtube {
constructor(httpClient) {
this.youtube = httpClient;
}
async mostPopular() {
const response = await this.youtube.get("videos", {
params: {
part: "snippet",
chart: "mostPopular",
maxResults: 24,
},
});
return response.data.items.map((item) => ({
...item,
id: item.id,
}));
}
async search(query) {
const response = await this.youtube.get("search", {
params: {
part: "snippet",
maxResults: 24,
type: "video",
q: query,
},
});
return response.data.items.map((item) => ({
...item,
id: item.id.videoId,
}));
}
}
export default Youtube;