본문 바로가기
Tutorial/youtube

19. 나만의 유튜브 사이트 만들기 : Rapid API 및 더보기 설정하기

by @webstoryboy 2023. 10. 16.
Tutorial/Portfolio

나만의 유튜브 사이트 만들기

by @webs 2023. 09. 01.
19
나만의 유튜브 사이트 만들기 : Rapid API 및 더보기 설정하기
난이도 중간

소개

안녕하세요! 웹스토리보이입니다. 이 강의는 React 프레임워크와 YouTube API를 이용하여 자신만의 간단한 영상 사이트를 만들어보겠습니다. React의 기본 개념을 이해하고, 컴포넌트를 구조화하고 상태를 관리하는 방법을 학습하게 될 것입니다. 또한 YouTube Data API를 활용하여 외부 데이터를 가져오는 방법을 익히고, API 응답을 처리하여 사용자에게 의미 있는 정보를 제공하는 방법을 이해하게 됩니다. 이로써 자신만의 유튜브 사이트를 만들고, 활용해보는 것을 목표로 합니다. 그럼 한번 시작해볼까요? 🥳

인덱스

  • 1. 셋팅하기
    • 1_1. Node.js 설치
    • 1_2. Vscode 설치
    • 1_3. React.js 설치
  • 2. 라이브러리 설치하기
    • 2_1. 폴더 정리하기
    • 2_2. 라이브러리 설치하기
  • 3. Git 연동하기
    • 3_1. 저장소 만들기
    • 3_2. 모든 파일 올리기
    • 3_3. 깃 상태 확인하기
  • 4. SCSS 셋팅하기
    • 4_1. SCSS 설정하기
    • 4_2. style.scss 설정하기
    • 4_3. fonts.scss 설정하기
    • 4_4. vars.scss 설정하기
    • 4_5. reset.scss 설정하기
    • 4_6. mixin.scss 설정하기
    • 4_7. common.scss 설정하기
  • 5. 페이지 만들기
    • 5_1. 페이지 만들기
    • 5_2. 페이지 컴퍼넌트 만들기
  • 6. 섹션 컴퍼넌트 구조화하기
    • 6_1. 전체 레이아웃 만들기
    • 6_2. 섹션 컴퍼넌트 만들기
  • 7. 헤더 영역 완성하기
    • 7_1. 헤더 영역 구조 잡기
    • 7_2. 헤더 영역 디자인 작업
  • 8. 헤더 영역 데이터 작업
    • 8_1. 헤더 영역 데이터 작업
    • 8_2. 반복문과 map()
    • 8_3. 메뉴 활성화하기
    • 8_4. 컴퍼넌트 세부화 시키기
  • 9. 컴퍼넌트 비동기 작업
    • 8_1. 컴퍼넌트 props 사용하기
    • 8_2. React.Suspense 사용하기
  • 10. 페이지 SEO 작업
    • 10_1. 메인 페이지 SEO 설정하기
    • 10_2. 모든 페이지 SEO 설정하기
  • 11. 메인 콘텐츠 작업
    • 11_1. 검색 컴퍼넌트 작업하기
    • 11_2. 메인 컴퍼넌트 작업하기
  • 12. 추천 영상 작업
    • 12_1. 메인 추천 영상 작업
    • 12_2. 추천 영상 반응형 작업
    • 12_3. 추천 영상 페이지 작업
  • 13. 추천 개발자 작업
    • 13_1. 메인 추천 개발자 작업
    • 13_2. 추천 개발자 페이지 작업
  • 14. 메인 섹션 나머지 콘텐츠 작업
    • 14_1. 웹디자인 기능사 컴퍼넌트 작업
    • 14_2. 웹표준 사이트 컴퍼넌트 작업
    • 14_3. GSAP 사이트 컴퍼넌트 작업
    • 14_4. 포트폴리오 사이트 컴퍼넌트 작업
    • 14_5. 유튜브 사이트 컴퍼넌트 작업
  • 15. 비디오 컴퍼넌트 통합 작업
    • 15_1. 공통 요소 컴퍼넌트 만들기
    • 15_2. Swiper 슬라이드 만들기
    • 15_3. 로딩 효과 넣기
  • 16. Swiper 이미지 슬라이드 작업
    • 16_1. 추천 개발자 이미지 슬라이드 작업
    • 16_2. 추천 개발자 로딩 효과 넣기
    • 16_3. 추천 영상 로딩 및 데이터 작업
  • 17. 나머지 페이지 작업
    • 17_1. 웹디자인 기능사 페이지 작업
    • 17_2. 웹표준 사이트 페이지 작업
    • 17_3. GSAP 페이지 작업
    • 17_4. 포트폴리오 페이지 작업
    • 17_5. 유튜브 페이지 작업
    • 17_6. 추천 개발자 페이지 작업
    • 17_7. 추천 영상 페이지 작업
  • 18. 검색 및 유튜브 API 설정하기
    • 18_1. 검색 영역 설정하기
    • 18_2. 유튜브 API 설정하기
    • 18_3. 유튜브 API 데이터 가져오기
  • 19. Rapid API 및 더보기 설정하기
    • 19_1. Rapid API 설정하기
    • 19_2. Rapid API 데이터 가져오기
    • 19_3. 검색 데이터 더보기 기능 설정하기
    • 19_4. Loading 소스 설정하기

19. Rapid API 및 더보기 설정하기

19_1. Rapid API 설정하기

이번에는 Youtube API가 아닌 rapid에서 제공하는 API로 작업하겠습니다. Youtube API 작업하다보면 트래픽이나 사용제한으로 오래동안 사용 못할 수 있습니다. 제한이 걸려 있기 때문에 만약을 위해서 Rapid API도 사용해보도록 하겠습니다. https://rapidapi.com/ 여기에서 회원가입을 하고 youtube v3를 검색합니다.

youtube2023

테스트도 바로 할 수 있으며, axios를 선택하여 소스도 확인할 수 있습니다.

youtube2023

19_2. Rapid API 데이터 가져오기

이번에는 axios를 통해 가져오겠습니다. 파일을 utils 폴더에 api.js 파일을 만들어서 다음과 같이 작업하겠습니다. 만약 데이터가 불러오지 않는다면 npm start를 다시 한번해주세요!

import axios from 'axios';

export const BASE_URL = 'https://youtube-v31.p.rapidapi.com';

const options = {
    params: {
        maxResults: 48,
    },
    headers: {
        'X-RapidAPI-Key': process.env.REACT_APP_RAPID_API_KEY,
        'X-RapidAPI-Host': 'youtube-v31.p.rapidapi.com',
    },
};

export const fetchFromAPI = async (url) => {
    const { data } = await axios.get(`${BASE_URL}/${url}`, options);
    console.log(data)
    return data;
};

Axios는 JavaScript 및 Node.js에서 사용할 수 있는 라이브러리로, HTTP 요청을 간단하게 만들고 처리하는데 도움을 주는 것이 주요 목적입니다. 주로 클라이언트 측 및 서버 측 개발에서 사용되며, 다음과 같은 주요 특징을 가지고 있습니다:

  • 간편한 HTTP 요청: Axios는 HTTP GET, POST, PUT, DELETE 등의 다양한 요청 메서드를 간편하게 만들어주며, 다른 HTTP 클라이언트보다 사용하기 쉽습니다.
  • Promise 기반: Axios는 Promise를 기반으로 동작하기 때문에 비동기적인 작업을 처리하기 용이합니다. 이로써 비동기 코드를 관리하고 오류 처리를 쉽게 할 수 있습니다.
  • 요청 및 응답 인터셉터: Axios는 요청과 응답을 인터셉트(intercept)하여 필요한 처리를 수행할 수 있게 해줍니다. 예를 들어, 요청 전에 인증 토큰을 추가하거나 응답을 처리하기 전에 데이터를 변환할 수 있습니다.
  • 자동 데이터 변환: Axios는 JSON 데이터를 자동으로 JavaScript 객체로 변환해주거나 반대로 JavaScript 객체를 JSON 문자열로 변환해주는 편리한 기능을 제공합니다.
  • HTTP 요청의 취소: Axios는 HTTP 요청을 중간에 취소할 수 있는 기능을 제공하여 불필요한 네트워크 요청을 방지할 수 있습니다.
  • 서버 및 브라우저 환경에서 사용 가능: Axios는 브라우저와 Node.js 환경에서 모두 사용 가능하므로, 클라이언트 측 및 서버 측 코드에서 동일한 코드를 사용할 수 있습니다.
  • 안전한 CSRF(Cross-Site Request Forgery) 보호: Axios는 기본적으로 CSRF를 방어하기 위한 설정을 포함하고 있어, 보안적인 측면에서도 강력한 도구로 사용됩니다.

pages 폴더에 Search.jsx 페이지는 다음과 같이 수정하겠습니다. 소스가 조금 더 심플해졌습니다.

import React, { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
import Main from '../components/section/Main'

import VideoSearch from '../components/videos/VideoSearch'
import { fetchFromAPI } from '../utils/api'

const Search = () => {
    const { searchId } = useParams();
    const [ videos, setVideos ] = useState([]);
    
    useEffect(() => {
        fetchFromAPI(`search?part=snippet&q=${searchId}`)
            .then((data) => setVideos(data.items))
    }, [searchId]);

    return (
        <Main 
            title = "유투브 검색"
            description="유튜브 검색 결과 페이지입니다.">
            
            <section id='searchPage'>
                <div className="video__inner search">
                    <VideoSearch videos={videos} />
                </div>
            </section>
        </Main>
    )
}

export default Search

.env 파일에는 다음 파일을 추가하겠습니다.

REACT_APP_RAPID_API_KEY=여기에 Rapid API 키를 넣습니다.

만약 이런 화면이 나온다면 API가 제대로 연결되어 있지 않았서 그렇습니다. 재부팅 부탁드려요! 그래도 안되면 API 번호나 오타를 확인해야 합니다.

youtube2023

19_3. 검색 데이터 더보기 기능 설정하기

검색 데이터가 많기 때문에 더 보기 버튼을 추가하여 버튼을 누르면 내용물을 더 보여주겠습니다. pages > search.jsx 페이지를 다시 수정하겠습니다.

import React, { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
import Main from '../components/section/Main'

import VideoSearch from '../components/videos/VideoSearch'
import { fetchFromAPI } from '../utils/api'

const Search = () => {
    const { searchId } = useParams();
    const [ videos, setVideos ] = useState([]);
    const [ nextPageToken, setNextPageToken ] = useState(null);
    
    useEffect(() => {
        setVideos([]);
        fetchVideos(searchId);
    }, [searchId]);

    const fetchVideos = (query, pageToken = '') => {
        fetchFromAPI(`search?part=snippet&q=${query}&pageToken=${pageToken}`)
            .then((data) => {
                setNextPageToken(data.nextPageToken);
                setVideos((prevVideos) => [...prevVideos, ...data.items]);
            })
            .catch((error) => {
                console.error('Error fetching data:', error);
            });
    };

    const handleLoadMore = () => {
        if (nextPageToken) {
            fetchVideos(searchId, nextPageToken);
        }
    };

    return (
        <Main 
            title = "유투브 검색"
            description="유튜브 검색 결과 페이지입니다.">
            
            <section id='searchPage'>
                <h2>🤠 <em>{searchId}</em> 검색 결과입니다.</h2>
                <div className="video__inner search">
                    <VideoSearch videos={videos} />
                </div>
                <div className="video__more">
                    {nextPageToken && (
                        <button onClick={handleLoadMore}>더 보기</button>
                    )}
                </div>
            </section>
        </Main>
    )
}

export default Search

이 컴포넌트는 YouTube API를 통해 검색 결과를 가져와 사용자에게 표시하고, 더 많은 결과를 불러올 수 있는 기능을 제공합니다. 결과를 동적으로 업데이트하고 더 많은 동영상을 불러오는 기능을 갖춘 검색 결과 페이지를 만들 수 있게 해주는 컴포넌트입니다.

  • nextPageToken 상태 변수: nextPageToken은 다음 페이지의 토큰을 저장합니다. 이를 사용하여 API 호출 시 다음 페이지의 결과를 가져옵니다. 초기값은 null로 설정됩니다.
  • useEffect로 초기 검색 결과 초기화: 검색어(searchId)가 변경될 때마다 videos 상태와 nextPageToken 상태를 초기화합니다. 이렇게 함으로써 새로운 검색어로 검색 결과를 다시 불러옵니다.
  • fetchVideos 함수: 검색 결과를 가져오는 로직을 함수로 추상화합니다. 함수에는 query (검색어)와 pageToken (다음 페이지 토큰)을 인자로 받습니다.
  • handleLoadMore 함수: "더 보기" 버튼 클릭 시 호출되는 함수로, nextPageToken이 있을 때만 추가 데이터를 로드합니다.
  • JSX에서 "더 보기" 버튼 추가: 검색 결과 아래에 "더 보기" 버튼을 추가하고, nextPageToken이 존재할 때만 이 버튼을 렌더링합니다. 버튼을 클릭하면 handleLoadMore 함수가 실행되어 추가 데이터를 가져옵니다.

CSS도 추가해주겠습니다. scss > section > _video.scss 파일에 추가하겠습니다.

.video__more {
    button {
        width: 100%;
        border: 0;
        padding: 20px;
        background-color: var(--black100);
        color: var(--white);
        transition: all 0.3s;
        margin-bottom: 20px;
        cursor: pointer;
        border-radius: 40px;

        &:hover {
            background-color: var(--black200);
        }
    }
}

19_4. Loading 소스 설정하기

기존 페이지처럼 로딩 소스를 추가하여 조금 더 부드럽게 작업하겠습니다. pages > Search.jsx 페이지를 다음과 같이 수정하겠습니다.

import React, { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
import Main from '../components/section/Main'

import VideoSearch from '../components/videos/VideoSearch'
import { fetchFromAPI } from '../utils/api'

const Search = () => {
    const { searchId } = useParams();
    const [ videos, setVideos ] = useState([]);
    const [ nextPageToken, setNextPageToken ] = useState(null);
    const [ loading, setLoading ] = useState(true); 
    
    useEffect(() => {
        setVideos([]);
        fetchVideos(searchId);
        setLoading(true);
    }, [searchId]);

    const fetchVideos = (query, pageToken = '') => {
        fetchFromAPI(`search?part=snippet&q=${query}&pageToken=${pageToken}`)
            .then((data) => {
                setNextPageToken(data.nextPageToken);
                setVideos((prevVideos) => [...prevVideos, ...data.items]);
                setLoading(false);
            })
            .catch((error) => {
                console.error('Error fetching data:', error);
                setLoading(false); 
            });
    };

    const handleLoadMore = () => {
        if (nextPageToken) {
            fetchVideos(searchId, nextPageToken);
        }
    };

    const searchPageClass = loading ? 'isLoading' : 'isLoaded';

    return (
        <Main 
            title = "유투브 검색"
            description="유튜브 검색 결과 페이지입니다.">
            
            <section id='searchPage' className={searchPageClass}>
                <h2>🤠 <em>{searchId}</em> 검색 결과입니다.</h2>
                <div className="video__inner search">
                    <VideoSearch videos={videos} />
                </div>
                <div className="video__more">
                    {nextPageToken && (
                        <button onClick={handleLoadMore}>더 보기</button>
                    )}
                </div>
            </section>
        </Main>
    )
}

export default Search

마무리

git 올리기

터미널에서 다음과 같이 작성하겠습니다. 새로운 페이지가 올라오는 것을 확인 할 수 있습니다.

webstoryboyhwang@Webstoryboyui-MacBookPro webs-youtube % git add .
webstoryboyhwang@Webstoryboyui-MacBookPro webs-youtube % git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
    (use "git restore --staged ..." to unstage)
        modified:   src/assets/scss/section/_video.scss
        modified:   src/pages/Search.jsx
        new file:   src/utils/api.js

webstoryboyhwang@Webstoryboyui-MacBookPro webs-youtube % git commit -m "Rapid API 및 더보기 설정하기"
[main f818a8a] Rapid API 및 더보기 설정하기
    3 files changed, 75 insertions(+), 14 deletions(-)
    create mode 100644 src/utils/api.js
webstoryboyhwang@Webstoryboyui-MacBookPro webs-youtube % git push -u origin main
Enumerating objects: 20, done.
Counting objects: 100% (20/20), done.
Delta compression using up to 10 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 2.00 KiB | 2.00 MiB/s, done.
Total 11 (delta 6), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (6/6), completed with 6 local objects.
To https://github.com/webstoryboy/webs-youtube.git
    787cb5e..f818a8a  main -> main
branch 'main' set up to track 'origin/main'.

이제 거의 완료가 되가고 있네요! 이제는 채널과 상세 비디오 페이지만 하면 됩니다. 조금만 더 힘내고 잘 따라와주세요. 오늘도 수고하셨습니다. 😘


예제 목록

댓글