React Sprint โŽฎ Video Player App(ft. YouTube Data API) - 2

NOWANDHEREยท2020๋…„ 11์›” 20์ผ
1

React

๋ชฉ๋ก ๋ณด๊ธฐ
2/2
post-thumbnail

Create myYouTube with React

๐ŸŒป ์ด๋ฒˆ ์Šคํ”„๋ฆฐํŠธ๋ฅผ ๊ฐ€์žฅ ์ฆ๊ฒ๊ฒŒ ๋ชฐ์ž…ํ–ˆ๋‹ค. ํ•ญ์ƒ ๊ทธ๋Ÿฌํ•˜๋“ฏ, ์ฒ˜์Œ์—๋Š” ์ •๋ง ๋ง‰๋ง‰ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฒ˜์Œ์œผ๋กœ API๋„ ์ ์šฉํ•ด๋ณด๊ณ  ๊ณ„์† ์•ˆ๋˜๋˜ ๊ฒƒ์ด ๊ฒฐ๊ตญ ๋  ๋•Œ, '์—ญ์‹œ ํ•˜๋ฉด ๋˜๋Š”๊ตฌ๋‚˜'๋ฅผ ๋˜ ํ•œ๋ฒˆ ๋Š๋ผ๊ฒŒ ํ•ด์ค€ ๊ณ ๋งˆ์šด ์Šคํ”„๋ฆฐํŠธ์˜€๋‹ค.

React Sprint โŽฎ Video Player App - 1


5. YouTube API์™€์˜ ์ƒํ˜ธ ์ž‘์šฉ ์„ค์ •


๋จผ์ € Google's YouTube API์— ์ ‘์†ํ•˜๊ณ 

ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.

YouTube Data API v3๋ฅผ ์„ ํƒํ–ˆ๋‹ค. (that provides access to YouTube data, such as videos, playli...๋ผ๊ณ  ์จ ์žˆ๊ธธ๋ž˜)

API ํ˜ธ์ถœ ์œ„์น˜๋Š” ์›น๋ธŒ๋ผ์šฐ์ €(์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ), ๋ฐ์ดํ„ฐ ์œ ํ˜•์€ public data๋ฅผ ์„ ํƒํ–ˆ๋‹ค.

API Key๋ฅผ ๋ฐ›์•˜๋‹ค!

์ด์ œ API๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฉด ์œ„ ์‚ฌ์ง„๊ณผ ๊ฐ™์€ ํ™”๋ฉด์ด ๋‚˜์˜ค๊ฒŒ ๋œ๋‹ค. ๊ทธ๋Ÿผ ์„ฑ๊ณต์ด๋‹ค. API key๋ฅผ ํ”„๋กœ์ ํŠธ ๋‚ด์˜ youtube.js ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ๋ณ€์ˆ˜์— ๋‹ด์•„๋‘์—ˆ๋‹ค.

6. ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” API ํ—ฌํผ ๋งŒ๋“ค๊ธฐ


์†”์งํžˆ ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ• ์ง€ ๊ฐ์ด ์žกํžˆ์ง€ ์•Š์•„์„œ ์ด ๋ถ€๋ถ„์— ์‹œ๊ฐ„์ด ์ •๋ง ๋งŽ์ด ์†Œ์š”๋๋‹ค. YouTube ๋™์˜์ƒ์„ ๊ฒ€์ƒ‰ํ•˜๋ ค๋ฉด API์˜ Search:lit ์—”๋“œํฌ์ธํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋ณด๋‹ค ์ฒด๊ณ„์ ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๋ ค๋ฉด, ์—”๋“œํฌ์ธํŠธ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ํ•œ๋‹ค. ์ฒ˜์Œ์—๋Š” ์ด ๋ง์ด ์ดํ•ด๊ฐ€ ์ž˜ ๋˜์ง€ ์•Š์•˜๋‹ค. ํ•˜์ง€๋งŒ API ๋ฌธ์„œ์— ๊ทธ ๋‹ต์ด ๋‚˜์™€ ์žˆ์—ˆ๋‹ค.

ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋จผ์ € API ๋ฌธ์„œ๋ฅผ ์œ ์‹ฌํžˆ ์‚ดํŽด๋ดค๋‹ค.

์ผ๋‹จ HTTP ์š”์ฒญ(GET) URL์€ ์ด๋ ‡๊ฒŒ ๋‚˜์™€์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ผ๋‹จ Postman์œผ๋กœ key ๊ฐ’์„ ์ž…๋ ฅํ•˜์—ฌ GET ์š”์ฒญ์„ ๋ณด๋‚ด๋ดค๋‹ค.

์˜ค.. ์‘๋‹ต์„ ๋ฐ›์•˜๋‹ค. ์‹ ๊ธฐํ–ˆ๋‹ค. '์•„, ์‘๋‹ต์„ ๋ฐ›์•„์„œ ์ด ์‘๋‹ต์„ ๊ฐ€๊ณตํ•˜๋Š” ๊ฒƒ์ด ํ—ฌํผ ํ•จ์ˆ˜์˜ ์—ญํ• ์ด๊ตฌ๋‚˜'๋ฅผ ๊นจ๋‹ฌ์•˜๋‹ค. ๊ตฌํ˜„ํ•ด๋ณด์ž. ์Šคํ”„๋ฆฐํŠธ์—์„œ ํ—ฌํผ ํ•จ์ˆ˜์˜ ์กฐ๊ฑด๊ณผ ์š”๊ตฌ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • XHR, fetch, jQuery ๋ฌด์—‡์ด๋“  ์ข‹๋‹ค. Search:list ์—”๋“œํฌ์ธํŠธ์— GET ์š”์ฒญ์„ ๋ณด๋‚ด๋ผ. ์ด๋ฒˆ ์Šคํ”„๋ฆฐํŠธ์—๋Š” XHR์„ ์„ ํƒํ–ˆ๋‹ค.

  • callback ํ•จ์ˆ˜๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„์•ผ ํ•œ๋‹ค. ์—”๋“œํฌ์ธํŠธ์— ํ˜ธ์ถœ ํ›„ ์‹คํ–‰ํ•˜๋Š” ํ•จ์ˆ˜์ด๊ณ , ์ด๋•Œ ์ฝœ๋ฐฑ์˜ ์ธ์ž(argument)๋Š” ๋น„๋””์˜ค ๋ฐฐ์—ด๋กœ ๋„˜๊ฒจ์•ผ ํ•œ๋‹ค.

  • ์˜ต์…˜์„ ๋‹ด๋Š” ๊ฐ์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š”๋‹ค.

  • query: ๊ฒ€์ƒ‰์–ด, ์ฆ‰ API ๋ฌธ์„œ์˜ q ๋งค๊ฐœ๋ณ€์ˆ˜์— ํ•ด๋‹นํ•œ๋‹ค.

  • max: ๊ฐ€์ ธ์˜ฌ ๋™์˜์ƒ์˜ ์ตœ๋Œ€ ๊ฐœ์ˆ˜์ด๋ฉฐ, ๊ธฐ๋ณธ๊ฐ’์€ 5์ด๋‹ค. ๊ทธ๋ž˜์„œ Postman์—์„œ ์‘๋‹ต์ด 5๊ฐœ๊ฐ€ ์™”๊ตฌ๋‚˜. API ๋ฌธ์„œ์—์„œ maxResults ๋งค๊ฐœ๋ณ€์ˆ˜์— ํ•ด๋‹น๋œ๋‹ค.

  • key: ์ธ์ฆ๋œ YouTube APIํ‚ค ์ž…๋‹ˆ๋‹ค. API ์š”์ฒญ์€ key ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ•ญ์ƒ ํฌํ•จํ•ด์•ผ ํ•œ๋‹ค.

  • API ํ˜ธ์ถœ ์‹œ, ๋‹ค์Œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ˜๋“œ์‹œ ๋„˜๊ฒจ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

  • part์˜ ๊ฐ’์€ snippet์œผ๋กœ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค.

  • type์˜ ๊ฐ’์€ video์œผ๋กœ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ฆฌํ•˜์—ฌ, searchYouYube.js์— ์žˆ๋Š” searchYouTube ํ•จ์ˆ˜๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ๋‹ค. XHR์„ ํ†ตํ•ด GET ์š”์ฒญ์„ ๋ณด๋ƒˆ๊ณ  ์œ„์—์„œ Postman์˜ ์‘๋‹ต์„ ๋ณด๊ณ  ์•Œ ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ ์‘๋‹ต์— ์„ฑ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ์‘๋‹ต ๋ณธ๋ฌธ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

response

{
  "kind": "youtube#searchListResponse",
  "etag": etag,
  "nextPageToken": string,
  "prevPageToken": string,
  "pageInfo": {
    "totalResults": integer,
    "resultsPerPage": integer
  },
  "items": [
    search Resource
  ]
}

์‘๋‹ต ๊ฐ์ฒด์˜ items ์†์„ฑ์— ๋น„๋””์˜ค ์ •๋ณด๋“ค์ด ๋“ค์–ด์žˆ๋‹ค.

response.items

{
  "kind": "youtube#searchResult",
  "etag": etag,
  "id": {
    "kind": string,
    "videoId": string,
    "channelId": string,
    "playlistId": string
  },
  "snippet": {
    "publishedAt": datetime,
    "channelId": string,
    "title": string,
    "description": string,
    "thumbnails": {
      (key): {
        "url": string,
        "width": unsigned integer,
        "height": unsigned integer
      }
    },
    "channelTitle": string
  }
}

๊ทธ๋Ÿฌ๋ฏ€๋กœ, callback ํ•จ์ˆ˜์— response.items ๋ฐฐ์—ด์„ ๋„˜๊ฒผ๋‹ค.

7. ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋กœ ์•ฑ ์ดˆ๊ธฐํ™”


์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ํ†ตํ•ฉํ•˜๊ธฐ ์œ„ํ•ด searchYouTube์—์„œ ๋ฆฌํ„ดํ•˜๋Š” ์‹ค์‹œ๊ฐ„ ๋™์˜์ƒ์„ ์ด์šฉํ•ด ์•ฑ์„ ๋ Œ๋”๋ง ํ•ด์•ผํ–ˆ๋‹ค. React life cycle์„ ์ดํ•ดํ•ด์•ผ ํ–ˆ๋Š”๋ฐ ์›Œ๋‚™ ํ›Œ๋ฅญํ•œ ๊ทธ๋ฆผ์ด ์žˆ๋‹ค.

componentDidMount()๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ–ˆ๋‹ค.

// App.js ์ƒ๋‹จ์— searchYouTube() ํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ „๋‹ฌํ•  ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ–ˆ๋‹ค.
const youTube = {
  query: 'parkhyoshin'
  max: 10,
  key: YOUTUBE_API_KEY,
};

// GET ์š”์ฒญ์„ ํ†ตํ•œ ์‘๋‹ต์„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜(searchYouTube)๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , 
// callback ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ฐ›์€ ๋ฐฐ์—ด result๋ฅผ setState()์„ ํ†ตํ•ด ์ƒํƒœ์— ์ ์šฉํ•œ๋‹ค.
componentDidMount() {
  searchYouTube(youTube, (result) => {
    this.setState({ videos: [...result], current: result[0] });
  });
} 

์œ„์˜ ๊ทธ๋ฆผ์„ ๋ด๋„ ๊ทธ๋ ‡๊ณ  componentDidMount() ๊ณต์‹ ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด componentDidMount()๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋œ ์งํ›„ ํ˜ธ์ถœ๋˜๊ณ , ์™ธ๋ถ€์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•œ๋‹ค๋ฉด, ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์ ์ ˆํ•œ ์œ„์น˜๋ผ๊ณ  ๋‚˜์™€์žˆ๋‹ค.

๋˜ํ•œ, componentDidMount()์—์„œ ์ฆ‰์‹œ setState()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ, ์ด๋กœ ์ธํ•˜์—ฌ ์ถ”๊ฐ€์ ์ธ ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜์ง€๋งŒ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•˜๊ธฐ ์ „์— ์ด๋ฃจ์–ด์งˆ ๊ฒƒ์ด๋‹ค. ์ด ๊ฒฝ์šฐ render()๊ฐ€ ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋˜์ง€๋งŒ, ์‚ฌ์šฉ์ž๋Š” ๊ทธ ์ค‘๊ฐ„ ๊ณผ์ •์„ ๋ณผ ์ˆ˜ ์—†์„ ๊ฒƒ์ด๋ผ๊ณ  ๋‚˜์™€ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ์‚ฌ์šฉ ๋ฐฉ์‹์€ ์„ฑ๋Šฅ ๋ฌธ์ œ๋กœ ์ด์–ด์ง€๊ธฐ ์‰ฌ์šฐ๋ฏ€๋กœ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

8. ์‹ค์‹œ๊ฐ„ ๊ฒ€์ƒ‰ ๊ตฌํ˜„


Search ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ–ˆ๋‹ค. <input> ์ƒ์ž์— ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•˜๊ณ , ๊ฒ€์ƒ‰ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ทธ ๋•Œ API๋ฅผ ์š”์ฒญํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ํ™”๋ฉด์— ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค. ์ตœ์ข… ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

App.js

import React from 'react';
import Nav from './Nav';
import VideoPlayer from './VideoPlayer';
import VideoList from './VideoList';
import { searchYouTube } from '../searchYouTube';
import { YOUTUBE_API_KEY } from '../../config/youtube';
import { fakeData } from './__test__/fakeData';

const youTube = {
  query: 'parkhyoshin',
  max: 10,
  key: YOUTUBE_API_KEY,
};

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      videos: fakeData,
      current: fakeData[0],
    };
    this.handleSearch = this.handleSearch.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }
  // API๋ฅผ ์š”์ฒญํ•˜๊ณ  ๊ทธ์— ๋”ฐ๋ฅธ ์‘๋‹ต์„ ์ƒํƒœ์— ๋ฐ˜์˜ํ•˜๋Š” ํ•จ์ˆ˜
  goToSearch() {
    searchYouTube(youTube, (result) => {
      this.setState({ videos: [...result], current: result[0] });
    });
  }
  // ๊ฒ€์ƒ‰ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ตœ์ข…์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜
  // ์ƒˆ๋กœ์šด ๊ฒ€์ƒ‰์–ด(newQuery)๋ฅผ ๋ฐ›์•„์„œ youTube ๊ฐ์ฒด์— ๋ฐ˜์˜ํ•˜๊ณ  goToSearch ๋ฉ”์†Œ๋“œ ์‹คํ–‰
  handleSearch(newQuery) {
    youTube.query = newQuery;
    this.goToSearch();
  }

  handleChange(videoKey) {
    for (let i = 0; i < this.state.videos.length; i++) {
      if (videoKey === this.state.videos[i].id.videoId) {
        this.setState({ current: this.state.videos[i] });
        break;
      }
    }
  }
  
  componentDidMount() {
    this.goToSearch();
  }
  
  render() {
    return (
      <div>
        // Nav ์ปดํฌ๋„ŒํŠธ์— handleSearch ํ•จ์ˆ˜ ์ „๋‹ฌ
        <Nav search={this.handleSearch} />
        <div className="parent">
          <VideoPlayer video={this.state.current}></VideoPlayer>
          <VideoList clickTitle={this.handleChange} videos={this.state.videos} />
        </div>
      </div>
    );
  }
}

export default App;

import React from 'react';
import Search from './Search';

const Nav = (props) => (
  <nav className="navbar">
    <div className="col-md-6 col-md-offset-3">
      // App ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ ํ•จ์ˆ˜ ๊ทธ๋Œ€๋กœ Search ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์ „๋‹ฌ
      <Search search={props.search} />
    </div>
  </nav>
);

export default Nav;

Search.js

import React from 'react';

const Search = (props) => {
  let query = '';
  // ๊ฒ€์ƒ‰ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋Š” ์ˆœ๊ฐ„ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜
  // Nav ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ props.search ํ•จ์ˆ˜ ํ˜ธ์ถœ
  const clickSearch = () => {
    props.search(query);
  };
  // query ๋ณ€์ˆ˜์— input์˜ ๋‚ด์šฉ์„ ๋‹ด์•„๋†“๋Š”๋‹ค
  const getInput = (e) => {
    query = e.target.value;
  };
  return (
    <div className="search-bar form-inline">
      // input์˜ ๋‚ด์šฉ์ด ๋ฐ”๋€”๋•Œ๋งˆ๋‹ค getInput ํ•จ์ˆ˜ ํ˜ธ์ถœ
      <input className="form-control" type="text" onChange={getInput} />
      // ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด clickSearch ํ•จ์ˆ˜ ํ˜ธ์ถœ
      <button className="btn hidden-sm-down" onClick={clickSearch}>
        ๊ฒ€์ƒ‰
      </button>
    </div>
  );
};

export default Search;

์ตœ์ข… ๊ฒฐ๊ณผ ํ™”๋ฉด


searchYouTube ํ•จ์ˆ˜์˜ ์ดˆ๊ธฐ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ youTube = { query: '์ง€๋“œ๋ž˜๊ณค', max: 10, key: YOUTUBE_API_KEY };๋กœ ์„ค์ •ํ•˜๊ณ , ๋ฐ•ํšจ์‹ ์„ ๊ฒ€์ƒ‰ํ•œ ๊ฒฐ๊ณผ์™€ ๋น„๋””์˜ค ์žฌ์ƒ๊นŒ์ง€ ๋‚˜ํƒ€๋‚˜๋Š” ํ™”๋ฉด์ด๋‹ค.

๋ฟŒ๋“ฏํ•˜๋‹ค.


Reference



๋งˆ์น˜๋ฉฐ


์งง๊ฒŒ๋‚˜๋งˆ ๋Š๋‚€ ์ ์„ ์ ์–ด๋ณด์ž. ์ •๋ง ๋งŽ์ด ๋ฐฐ์› ๋‹ค. ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๋‚ด์šฉ์ด ์ •๋ง ๋งŽ๊ณ  ๋ฆฌ์•กํŠธ์— ์ข€ ๋” ์ต์ˆ™ํ•ด์งˆ ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐ„์ด์—ˆ๋‹ค. ๋‹จ์‹œ๊ฐ„์— ๋งŽ์€ ๊ฐœ๋…์ด ๋จธ๋ฆฟ์†์œผ๋กœ ๋“ค์–ด์™€์„œ ํ˜ผ๋ž€์Šค๋Ÿฝ์ง€๋งŒ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ณต์Šตํ•ด๋ด์•ผ๊ฒ ๋‹ค.

์ฝ”๋“œ๋ฅผ ์ง€๊ธˆ ๋‹ค์‹œ ๋ด๋„ ๊ณ ์น˜๊ณ  ์‹ถ์€ ๋ถ€๋ถ„(State์˜ default ๊ฐ’์— fakeData๋ฅผ ๋‹ด์•„๋†“์€ ๊ฒƒ์ด๋ผ๋“ ์ง€, ๊ณต์‹ ๋ฌธ์„œ๊ฐ€ render()๋ฅผ ๋‘ ๋ฒˆ ํ•ด๋„ ์‚ฌ์šฉ์ž์˜ ๋ˆˆ์— ์•ˆ ๋ณด์ผ ๊ฒƒ์ด๋ผ ํ–ˆ๋Š”๋ฐ ์ž˜ ๋ณด์ธ๋‹ค)์ด ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฌด์—‡๋ณด๋‹ค๋„ ๋ฟŒ๋“ฏํ•œ ๊ฐ์ •์„ ์ˆจ๊ธธ ์ˆ˜๊ฐ€ ์—†๋‹ค. ์ ์–ด๋„ ๋‚˜์—๊ฒŒ๋Š” ๊ฐœ๋ฐœ ๊ณผ์ •์ด ๊ฒฐ์ฝ” ์‰ฝ์ง€ ์•Š์•˜๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ ์—ญ์‹œ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ž์‹ ๊ฐ์„ ์–ป์€ ๊ฒƒ ๊ฐ™์•„ ๊ธฐ์˜๋‹ค. ์•ž์œผ๋กœ๋„ ํ•˜๋ฃจํ•˜๋ฃจ ์ฆ๊ฒ๊ฒŒ ์ฝ”๋”ฉํ•ด์•ผ๊ฒ ๋‹ค!

๋ฐฐ์šฐ๋Š” ๋‹จ๊ณ„๋ผ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ‹€๋ฆฐ ๋‚ด์šฉ์€ ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์‹œ๋ฉด ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :)


profile
๐ŸŒป

0๊ฐœ์˜ ๋Œ“๊ธ€