๐Ÿชด React

[React/JS/ํŒ€ํ”„์ ] api๋กœ ๋ฐ›์€ ์ •๋ณด useState ๋ฐฐ์—ด์— ๋‹ด์•„ map ๋Œ๋ฆฌ๋ฉฐ ์ถœ๋ ฅํ•˜๊ธฐ

๋ จ๋”” 2024. 2. 27. 23:55
SMALL

 

ํ”„๋กœ์ ํŠธ ๋ฉ”์ธํŽ˜์ด์ง€์—์„œ

ํ•„์š”ํ•œ ์ •๋ณด๋“ค์„ api - axios get ํ•ด์„œ ๊ฐ€์ ธ์˜ค๊ณ ,

๊ทธ ์ •๋ณด๋“ค์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ฌถ์–ด, ๋ฐฐ์—ด state (useState) ์— ํ•˜๋‚˜์”ฉ ๋‹ด๊ณ  map์œผ๋กœ ๋Œ๋ฆฌ๋ฉด์„œ ์ถœ๋ ฅํ–ˆ๋‹ค.

<Thumbnail>์€ ์ปดํฌ๋„ŒํŠธ ! 

 

๊ทธ ์™ธ์—๋„ input์— ๋ถ€์—ฌํ•˜๋Š” onKeyDown ์†์„ฑ ๋“ฑ์„ ๋ฐฐ์› ๋‹ค.

์ด๋ฒˆ์—๋Š” trim() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋„ ์ถ”๊ฐ€ !

 

 

 

(๋‹ค๋ฅธ ๋ถ„๋“ค์ด ์“ฐ์‹  ์ฝ”๋“œ๋„ ์žˆ์Œ /์Šคํƒ€์ผ์ปดํฌ๋„ŒํŠธ ๋ถ€๋ถ„์€ ์ƒ๋žต)

 

์œ ํŠœ๋ธŒ api ํ†ตํ•ด ๊ฐ€์ ธ์˜จ ์ •๋ณด -> ์ธ๊ธฐ๊ธ‰์ƒ์Šน์˜์ƒ๋“ค์˜ ์ฑ„๋„ ์ •๋ณด ~ ์œ ํŠœ๋ธŒ์ธ๋„ค์ผ์ด๋ฏธ์ง€(์ฃผ์†Œ), ์œ ํŠœ๋ธŒ์ฑ„๋„๋ช…, ์œ ํŠœ๋ธŒcustomUrl

 

 

import { useEffect, useState } from 'react';
import styled from 'styled-components';
import HeaderSlider from '../sliders/HeaderSlider';
import { useMostPopularVideos } from '../../hooks/useMostPopularChannel';
import { getMostChannelInfo, getMostPopularThumbnails } from '../../api/dataApi';
import Thumbnail from '../main/Thumbnail';
import { useNavigate } from 'react-router-dom';
import BodySlider from '../sliders/BodySlider';

export default function Main() {
  const navigate = useNavigate();

  const [channelInfos, setChannelInfos] = useState([]);
  const { data: videos, isLoading, isError } = useMostPopularVideos();
  const [searchTerm, setSearchTerm] = useState('');

  const searchIconSrc = 'https://s3.ap-northeast-2.amazonaws.com/cdn.wecode.co.kr/icon/search.png';
  const keyWords = ['๋จน๋ฐฉ', '์—ฌํ–‰', '์ƒํ™œ', '์šด๋™', '๋ทฐํ‹ฐ', 'ํŒจ์…˜'];
  const order = ['1st', '2nd', '3rd', '4th', '5th'];

  useEffect(() => {
    const getThumbnails = async () => {
      if (videos) {
        const newChannelInfos = [];
        for (const video of videos.slice(0, 5)) {
          const channelTitle = video.snippet.channelTitle;
          const channelThumbnail = (await getMostPopularThumbnails(video.snippet.channelId)).high.url;
          const channelCustomUrl = await getMostChannelInfo(video.snippet.channelId);
          const channelUrl = `https://www.youtube.com/${channelCustomUrl}`;
          const channelInfo = { channelTitle, channelThumbnail, channelUrl };
          // console.log(channelThumbnail);
          newChannelInfos.push(channelInfo);
        }
        setChannelInfos(newChannelInfos);
      }
    };
    getThumbnails();
  }, [videos]);

  const handleSearchInputChange = (e) => {
    setSearchTerm(e.target.value);
  };

  // Enter ํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ ๊ฒ€์ƒ‰ (=> ๋ฆฌ์ŠคํŠธํŽ˜์ด์ง€๋กœ ์ด๋™)
  const handleSearchEnter = (e) => {
    if (e.key === 'Enter') {
      if (!searchTerm.trim()) {
        return alert('๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.');
      }
      navigate(`/list/${searchTerm}`);
    }
  };

  // ๊ฒ€์ƒ‰์•„์ด์ฝ˜ ๋ˆŒ๋Ÿฌ ๊ฒ€์ƒ‰ (=> ๋ฆฌ์ŠคํŠธํŽ˜์ด์ง€๋กœ ์ด๋™)
  const handleSearchClick = () => {
    if (!searchTerm.trim()) {
      return alert('๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.');
    }
    navigate(`/list/${searchTerm}`);
  };

  const handleKeyWordClick = (keyword) => {
    navigate(`/list/${keyword}`);
  };

  const handleChannelClick = (channelUrl) => {
    window.open(channelUrl, '_blank');
  };

  if (isLoading) return <div>..Loading</div>;

  if (isError) return <div>{isError.message}</div>;

  return (
    <MainWrap>
      <HeaderSlider />
      <MainSearch>
        <SearchInputBox>
          <input
            id="search-input"
            type="search"
            placeholder="์›ํ•˜๋Š” ์ฃผ์ œ๋ฅผ ๊ฒ€์ƒ‰ํ•ด๋ณด์„ธ์š” !"
            value={searchTerm}
            onChange={handleSearchInputChange}
            onKeyDown={handleSearchEnter}
          />
          <img src={searchIconSrc} onClick={handleSearchClick} />
        </SearchInputBox>
        <SearchKeyWord>
          {keyWords.map((keyword) => {
            return (
              <KeywordText key={keyword} onClick={() => handleKeyWordClick(keyword)}>
                #{keyword}
              </KeywordText>
            );
          })}
        </SearchKeyWord>
      </MainSearch>
      <BodySlider />
      <MainBest>
        <MainBestTitle>
          <h3>Best YouTuber</h3>
          <p>์ด๋‹ฌ์˜ ์ธ๊ธฐ ์œ ํŠœ๋ฒ„</p>
        </MainBestTitle>
        <MainBestContWrap>
          {channelInfos.map((channelInfo, index) => (
            <BestYoutuber>
              <p>{order[index]}</p>
              <Thumbnail
                handleChannelClick={handleChannelClick}
                channelUrl={channelInfo.channelUrl}
                key={index}
                src={channelInfo.channelThumbnail}
                alt={`Thumbnail ${index + 1}`}
              />
              <p>{channelInfo.channelTitle}</p>
            </BestYoutuber>
          ))}
        </MainBestContWrap>
      </MainBest>
    </MainWrap>
  );
}
SMALL