프론트엔드✏️/개인공부

[youtube] tailwind grid auto-fill, router, axios 리팩토링

당근먹는하니 2023. 1. 13. 14:36
728x90
반응형

tailwind에서 auto-fill쓰기

// tailwind.config.js
module.exports = {
  content: ["./src/**/*.{html,js,jsx,ts,tsx}"],
  theme: {
    gridTemplateColumns: {
      "fill-auto": "repeat(auto-fill, minmax(15rem, 1fr))",
    },
  },
  plugins: [require("@tailwindcss/line-clamp")],
};

쓰고 적용할 곳에

grid-cols-fill-auto 라고 써주면 된다. 

https://github.com/tailwindlabs/tailwindcss/issues/1403

 

[Feature request] CSS Grid - Auto-Fit & Auto-Fill · Issue #1403 · tailwindlabs/tailwindcss

So happy that Tailwind finally have css grid support built-in 👍 The only thing i've been missing, when working with tailwinds grid utilities are Auto-Fit & Auto-Fill Any plans to add them i...

github.com

 

해야하는 것, 채널아이디로 채널 정보 가져와서 썸네일 보여주기

 

- header 태그 쓰기

- Home 이동시 검색창 비우기

- input에 type="text"쓰기 

- 검색화면 뒤로가기: keyword가 있다면 text 업데이트 해주기

- body { 100vw 100vh }

- #root { @apply w-full max-w-screen-2xl } 하면 내가 약간 끙끙대던 문제 한 번에 해결...

- response를 받아서 json()한 뒤 거기서 data를 리턴하거나 data. ... 의 하위 아이템을 리턴하거나

- api는 분리하기

- # (private) 내부적으로 호출

 

c++때처럼 클래스 인스턴스 생성 후에 내장 함수 쓰는 방식... 

 

 

강의를 들으면서 내가 react-router를 잘 못쓰고 있었다는 것을 깨달았다. 

app.js에 해도 상관이 없는건진 모르겠는데 강의에서는 index.js에 router를 설정했다. 

 

구조도 좀 이상하게 짜놨다. 

videos 통일성을 주는 게 좋을 것 같다... 난 근데 주소도 여러개고 컴포넌트도 여러개

주소라도 좀 예쁘게 고쳐봐야겠다. 

 

 

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    errorElement: (
      <div className="mx-auto h-screen bg-slate-700 text-white">
        미안해요🥲오류가 났어요
      </div>
    ),
    children: [
      {
        index: true,
        element: <Home />,
      },
      {
        path: "/videos",
        element: <Home />,
      },
      {
        path: "/videos/:keyword",
        element: <SearchVideo />,
      },
      {
        path: "/videos/watch/:id",
        element: <VideoDetail />,
      },
    ],
  },
]);

이렇게 수정했다. 

element <Videos /> 로 활용 못 하고 searchVideo로 나눠놓은게 아쉽다. 

 

그리고 제일 이해할 수 없었던 부분,

나는  graphQL위주로..배우기도 했고...이건 변명이지만... 

직접 fetch해오는 것에 낯설다. 근데 거기에 axios를 추가한... 그리고 Fake랑 찐 두 개로 나뉘는... 

일단 컴포넌트에선 통신을 하지 않고 따로 분리하는 게 좋다는 건 알겠다. 

 

일단 src 폴더 밑에 api 폴더를 만든다. 

그 안에 youtube.js 파일을 생성 

 

// src/api/youtube.js

import axios from "axios";

export async function search(keyword) {
     return axios.get(`/videos/${keyword ? 'search' : 'popular'}.json`)
     .then((res)=> res.data.items)
}

 

음...그리고 콜백함수로 전달해주면 되는데 나는 popular랑 search 쿼리를 다르게 쓰고 있는 것 같다.ㅎㅎ

아예 컴포넌트가 다르니까.... 으아아아앙아 ㅠㅠㅠ

쓰면서도 이상하긴 했어... 

 

// Home.jsx
import React from "react";
import Video from "../video/Video";
import { useQuery } from "react-query";
import Loading from "../../commons/loading/Loading";

export default function Home() {


  const apiKey = process.env.REACT_APP_YOUTUBE_API_KEY;

  const {
    isLoading,
    error,
    data: popularVideos,
  } = useQuery(
    ["videos", "popular"],
    async () => {
      return fetch(
        `https://youtube.googleapis.com/youtube/v3/videos?part=snippet&chart=mostPopular&regionCode=KR&maxResults=25&key=${apiKey}`
      ).then((res) => {
        return res.json();
      });
    },
    {
      staleTime: 1000 * 60 * 3,
    }
  );

  // console.log("popular::::", popularVideos);
  return (
    <div className="w-full bg-neutral-900 text-white">
      {isLoading && <Loading />}
      <div className="grid grid-cols-fill-auto gap-2">
        <Video category={popularVideos} />
      </div>
    </div>
  );
}

// SearchVideo.jsx
import React, { useEffect } from "react";
import { useQuery } from "react-query";
import { useParams } from "react-router-dom";
import Loading from "../../commons/loading/Loading";
import Video from "../video/Video";

export default function SearchVideo() {
  const { keyword } = useParams();
  const apiKey = process.env.REACT_APP_YOUTUBE_API_KEY;

  useEffect(() => {
    searchRefetch();
  }, [window.location.pathname]);

  const {
    isLoading,
    error,
    data: searchVideos,
    refetch: searchRefetch,
  } = useQuery(
    ["videos", keyword],
    async () => {
      return fetch(
        `https://youtube.googleapis.com/youtube/v3/search?part=snippet&maxResults=25&q=${keyword}&key=${apiKey}`
      ).then((res) => {
        return res.json();
      });
    },
    {
      staleTime: 1000 * 60 * 3,
      enabled: false,
    }
  );
  return (
    <div className="w-full bg-neutral-900 text-white">
      {isLoading && <Loading />}

      <div className="grid grid-cols-fill-auto gap-2">
        <Video category={searchVideos} />
      </div>
    </div>
  );
}

지금 이렇게 되어있는데, 둘이 합쳐야할 것 같다. 

 

오싹,,,,,,

기나오싹,,, 

 

합치는 건 쉬웠다. 이름은... Videos로 바꾸면 좋을 것 같지만 일단 냅뒀다. 

import React from "react";
import Video from "../video/Video";
import { useQuery } from "react-query";
import Loading from "../../commons/loading/Loading";
import SearchVideo from "../search_video/SearchVideo";
import { useParams } from "react-router-dom";

export default function Home() {
  const { keyword } = useParams();

  const {
    isLoading,
    error,
    data: videos,
  } = useQuery(["videos", keyword], async () => SearchVideo(keyword), {
    staleTime: 1000 * 60 * 3,
  });

  // console.log("popular::::", popularVideos);
  return (
    <div className="w-full bg-neutral-900 text-white">
      {isLoading && <Loading />}
      <div className="grid grid-cols-fill-auto gap-2">
        <Video category={videos} />
      </div>
    </div>
  );
}

 

// src/api/Youtube.js

import axios from "axios";
const apiKey = process.env.REACT_APP_YOUTUBE_API_KEY;

export default class Youtube {
  constructor() {
    this.httpClient = axios.create({
      baseURL: "https://www.googleapis.com/youtube/v3",
      params: { key: apiKey },
    });
  }

  async search(keyword) {
    return keyword ? this.#searchByKeyword(keyword) : this.#mostPopular();
  }

  async #searchByKeyword(keyword) {
    return this.httpClient
      .get(`search`, {
        params: {
          part: "snippet",
          maxResults: 25,
          type: "video",
          q: keyword,
        },
      })
      .then((res) => res.data.items)
      .then((items) => items.map((item) => ({ ...item, id: item.id.videoId })));
  }

  async #mostPopular() {
    return this.httpClient
      .get(`videos`, {
        params: {
          part: "snippet",
          maxResults: 25,
          chart: "mostPopular",
        },
      })
      .then((res) => res.data.items);
  }
}

axios.create()로 인스턴스 생성

axios.create([config])
const instance = axios.create({
  baseURL: 'https://some-domain.com/api/',
  headers: { 'X-Custom-Header': 'foobar' },
  timeout: 1000,
});

인스턴스 메서드 .get, .post, .put 등을 쓸 수 있다. 

 

https://yamoo9.github.io/axios/guide/api.html#%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EC%83%9D%EC%84%B1

 

API | Axios 러닝 가이드

API 구성(configuration) 설정을axios()에 전달하여 요청할 수 있습니다. axios(config) axios({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' } }); 1 2 3 4 5 6 7 8 9 axios({ method:'get', url:'http://bit

yamoo9.github.io

 

 // Home.jsx 
 
 const {
    isLoading,
    error,
    data: videos,
  } = useQuery(
    ["videos", keyword],
    () => {
      const youtube = new Youtube();
      return youtube.search(keyword);
    },
    {
      staleTime: 1000 * 60 * 3,
    }
  );
728x90
반응형