본문 바로가기
Tutorial/youtube

09. 나만의 유튜브 사이트 만들기 : 컴퍼넌트 비동기 작업

by @webstoryboy 2023. 9. 8.
Tutorial/Portfolio

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

by @webs 2023. 09. 01.
09
나만의 유튜브 사이트 만들기 : 컴퍼넌트 비동기 작업
난이도 중간

소개

안녕하세요! 웹스토리보이입니다. 이 강의는 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 사용하기

9. 컴퍼넌트 비동기 작업

9_1. 컴퍼넌트 props 사용하기

메인 페이지의 props를 이용하여 메뉴를 클릭할 때마다 해당 콘텐츠가 보이도록 하겠습니다. 이럴 때 props를 이용하여 데이터를 전달하고 컨트롤 할 수 있습니다.

import React from 'react'

const Main = ( props ) => {
    return (
        <main id="main" role="main">
            {props.children}
        </main>
    )
}

export default Main

React에서 "props"는 "properties"의 줄임말로, 컴포넌트 간에 데이터를 전달하고 컴포넌트를 구성하는 데 사용되는 매개변수와 같은 역할을 합니다. Props는 React 컴포넌트 간에 데이터를 전달하거나 컴포넌트의 동작을 제어하기 위해 사용됩니다.

props.children을 사용하면 부모 컴포넌트가 자식 요소를 포함한 컴포넌트를 작성할 때 렌더링 구조를 더 유연하게 만들 수 있습니다. 이를 통해 동적으로 자식 요소를 추가하거나 조작할 수 있으며, 컴포넌트 간에 재사용 가능한 레이아웃 및 컨테이너 컴포넌트를 작성할 때 유용합니다.

이렇게 하면 메뉴를 누를 때마다 메인 영역이 변경되는 것을 확인할 수 있습니다.

youtube2023

9_2. React.Suspense 사용하기

React.Suspense는 React에서 비동기적으로 데이터나 컴포넌트를 불러오는 과정에서 대기 상태를 처리하기 위한 컴포넌트입니다. 이 컴포넌트를 사용하면 데이터나 컴포넌트가 로딩되기를 기다릴 수 있으며, 로딩 중에는 대체 컨텐츠(로딩 스피너 또는 로딩 메시지)를 표시할 수 있습니다. React.Suspense를 사용하면 코드 스플리팅, 데이터 로딩, 서버 사이드 렌더링과 같은 시나리오에서 사용자 경험을 향상시키는 데 도움이 됩니다.

우리 사이트의 모든 페이지는 왼쪽에 메뉴가 있고 오른쪽에 데이터가 로딩되기 때문에 이 방식을 사용할 것입니다. 이 방법을 사용하기 위해서는 app.js를 다시 재 작업 해주겠습니다. 기존 컴퍼넌트 방법이 변경되고 headerfooterMain 컴퍼넌트로 넘겨주겠습니다.

import React, { Suspense, lazy } from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Main from './components/section/Main';

const Home = lazy(() => import('./pages/Home'));
const Today = lazy(() => import('./pages/Today'));
const Developer = lazy(() => import('./pages/Developer'));
const Webd = lazy(() => import('./pages/Webd'));
const Website = lazy(() => import('./pages/Website'));
const Gsap = lazy(() => import('./pages/Gsap'));
const Port = lazy(() => import('./pages/Port'));
const Youtube = lazy(() => import('./pages/Youtube'));
const Channel = lazy(() => import('./pages/Channel'));
const Video = lazy(() => import('./pages/Video'));
const Search = lazy(() => import('./pages/Search'));
const Not = lazy(() => import('./pages/Not'));

const App = () => {
    return (
        <BrowserRouter>
            <Suspense fallback={<Main />}>
                <Routes>
                    <Route path='/' element={<Home />} />
                    <Route path="/today" element={<Today />} />
                    <Route path="/developer" element={<Developer />} />
                    <Route path="/webd" element={<Webd />} />
                    <Route path="/website" element={<Website />} />
                    <Route path="/gsap" element={<Gsap />} />
                    <Route path="/port" element={<Port />} />
                    <Route path="/youtube" element={<Youtube />} />
                    <Route path='/channel/:channelId' element={<Channel />} />
                    <Route path='/video/:videoId' element={<Video />} />
                    <Route path='/search/:searchId' element={<Search />} />
                    <Route path="*" element={<Not />} />
                </Routes>
            </Suspense>
        </BrowserRouter>
    );
}

export default App;
  • BrowserRouter : React Router에서 사용되는 브라우저 라우터 컴포넌트입니다. 브라우저 히스토리 API를 사용하여 라우팅을 처리합니다.
  • Suspense : Suspense 컴포넌트는 비동기적으로 로드되는 컴포넌트의 로딩 상태를 관리하는 데 사용됩니다. 여기서는 fallback 속성을 사용하여 로딩 중에 <Main /> 컴포넌트를 표시합니다.
  • Routes : Routes 컴포넌트는 각 경로에 대한 라우트를 정의하고, 해당 경로에 접근할 때 렌더링될 컴포넌트를 결정합니다.
  • Route : Route 컴포넌트는 특정 경로에 대한 라우팅 규칙을 설정하며, element 속성을 통해 해당 경로에 접근할 때 렌더링될 컴포넌트를 지정합니다.
  • lazy() : lazy() 함수는 코드 스플리팅을 위해 사용되며, 비동기적으로 컴포넌트를 로드합니다. 컴포넌트가 필요할 때 비동기적으로 불러와서 번들 크기를 줄일 수 있습니다.
  • fallback : fallback 속성은 Suspense 컴포넌트에서 로딩 중에 표시할 컴포넌트를 지정합니다. 여기서는 <Main /> 컴포넌트가 로딩 중에 보여집니다.

Main.js를 수정하겠습니다.

import React from 'react'

import Header from './Header'
import Footer from './Footer'

const Main = ( props ) => {
    return (
        <>
            <Header />
            <main id="main" role="main">
                {props.children}
            </main>
            <Footer />
        </>
    )
}

export default Main

<></>는 React에서 Fragments(프래그먼트)를 생성하기 위한 단축 구문입니다. Fragment는 React 컴포넌트의 반환 값으로 여러 요소를 래핑하고, 이러한 요소가 부모 요소 하나로 묶이지 않도록 허용하는 데 사용됩니다. React 컴포넌트는 루트 요소에서 시작해야 하기 때문에 여러 요소를 반환하려면 불필요한 부모 요소를 추가하게 됩니다. 이러한 상황에서 Fragment를 사용하면 불필요한 부모 요소 없이 여러 요소를 그룹화할 수 있습니다.

이제 모든 페이지도 다 변경해주어야 합니다.

import React from 'react'
import Main from '../components/section/Main'

const Channel = () => {
    return (
        <Main>
            Channel
        </Main>
    )
}

export default Channel
import React from 'react'
import Main from '../components/section/Main'

const Developer = () => {
    return (
        <Main>
            Developer
        </Main>
    )
}

export default Developer
import React from 'react'
import Main from '../components/section/Main'

const Gsap = () => {
    return (
        <Main>
            Gsap
        </Main>
    )
}

export default Gsap
import React from 'react'
import Main from '../components/section/Main'

const Home = () => {
    return (
        <Main>
            Home
        </Main>
    )
}

export default Home
import React from 'react'
import Main from '../components/section/Main'

const Not = () => {
    return (
        <Main>
            Not
        </Main>
    )
}

export default Not
import React from 'react'
import Main from '../components/section/Main'

const Port = () => {
    return (
        <Main>
            Port
        </Main>
    )
}

export default Port
import React from 'react'
import Main from '../components/section/Main'

const Search = () => {
    return (
        <Main>
            Search
        </Main>
    )
}

export default Search
import React from 'react'
import Main from '../components/section/Main'

const Today = () => {
    return (
        <Main>
            Today
        </Main>
    )
}

export default Today
import React from 'react'
import Main from '../components/section/Main'

const Video = () => {
    return (
        <Main>
            Video
        </Main>
    )
}

export default Video
import React from 'react'
import Main from '../components/section/Main'

const Wedd = () => {
    return (
        <Main>
            Wedd
        </Main>
    )
}

export default Wedd
import React from 'react'
import Main from '../components/section/Main'

const Website = () => {
    return (
        <Main>
            Website
        </Main>
    )
}

export default Website
import React from 'react'
import Main from '../components/section/Main'

const Youtube = () => {
    return (
        <Main>
            Youtube
        </Main>
    )
}

export default Youtube

마무리

git 올리기

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

webstoryboy@Webstoryboyui-iMac webs-youtube % git add .
webstoryboy@Webstoryboyui-iMac 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/App.js
        modified:   src/components/section/Main.jsx
        modified:   src/pages/Channel.jsx
        modified:   src/pages/Developer.jsx
        modified:   src/pages/Gsap.jsx
        modified:   src/pages/Home.jsx
        modified:   src/pages/Not.jsx
        modified:   src/pages/Port.jsx
        modified:   src/pages/Search.jsx
        modified:   src/pages/Today.jsx
        modified:   src/pages/Video.jsx
        modified:   src/pages/Webd.jsx
        modified:   src/pages/Website.jsx
        modified:   src/pages/Youtube.jsx

webstoryboy@Webstoryboyui-iMac webs-youtube % git commit -m "컴퍼넌트 비동기 작업"
[main 0aa59a8] 컴퍼넌트 비동기 작업
    14 files changed, 103 insertions(+), 62 deletions(-)
webstoryboy@Webstoryboyui-iMac webs-youtube % git push -u origin main
Enumerating objects: 39, done.
Counting objects: 100% (39/39), done.
Delta compression using up to 8 threads
Compressing objects: 100% (20/20), done.
Writing objects: 100% (20/20), 1.91 KiB | 1.91 MiB/s, done.
Total 20 (delta 14), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (14/14), completed with 3 local objects.
To https://github.com/webstoryboy/webs-youtube.git
    1f73d2f..0aa59a8  main -> main
branch 'main' set up to track 'origin/main'.

모든 페이지 구성이 비슷하기 때문에 메인 콘텐츠만 비동기 방식을 사용하여 데이터를 로드할 수 있도록 설정했습니다. 이렇게 하면 사이트 전환시 또는 메뉴 선택시 깜박임이나 전체 소스를 다시 다운 받는 경우를 막을 수 있습니다. 표면적으로 티는 잘 나지 않지만 사이트 규모가 커지고, 데이터 전송이 많을 때 조금 더 효율적으로 쓰기 위함입니다. 수고하셨습니다 🤩


예제 목록

댓글