스나이퍼팩토리 사전직무교육 (Day6)

짜스의 하루 ·2024년 9월 29일

리액트 데이터통신

데이터 통신

리액트에서 데이터 통신을 할 때는 axios 라이브러리나 fetch API를 사용하여 처리한다.
여러가지 편의 기능은 axios 라이브러리가 더 뛰어나지만, 별도의 라이브러리를 설치해서 사용해야 한다는 단점이 있다.

fetch API

React에서 fetch API를 사용하여 데이터를 불러오는 것은 일반적인 비동기 작업이다.
--> 데이터를 불러오는 과정에서 React의 useEffect 훅을 자주 사용하여 컴포넌트가 렌더링되었을 때 데이터를 가져온다.

fetch API를 활용해서 TMBD에 있는 데이터를 받아와서 MOVIE LIST를 불러오는 Simple Movie 사이트를 생성해보자

movieAPI

export const API_KEY = '5f90a5ae964c1e681e56c236101a5b46';
export const BASE_PATH = 'https://api.themoviedb.org/3';

export interface IMovie {
  id: number;
  backdrop_path: string;
  poster_path: string;
  title: string;
  overview: string;
  vote_average: string;
  release_date: string;
  genre_ids: [];
}

export interface IGetMoviesResult {
  dates: {
    maximum: string;
    minimum: string;
  };
  page: number;
  total_pages: number;
  total_results: number;
  results: IMovie[];
}

export async function getMovies(): Promise<IGetMoviesResult> {
  const response = await fetch(
    `${BASE_PATH}/movie/now_playing?api_key=${API_KEY}&language=ko-KR`
  );
  if (!response.ok) {
    throw new Error('현재 상영 중인 영화를 가져오지 못했습니다.');
  }
  return response.json();
}

export async function getTopRatedMovies(): Promise<IGetMoviesResult> {
  const response = await fetch(
    `${BASE_PATH}/movie/top_rated?api_key=${API_KEY}&language=ko-KR`
  );
  if (!response.ok) {
    throw new Error('Top Rated 영화를 가져오지 못했습니다.');
  }
  return response.json();
}

우선 나는 interface로 받아올 수 있는 데이터의 타입을 지정을 해준뒤,
그 타입을 fetch 함수에 연결해서, 데이터를 가져왔을 때, 쉽게 사용할 수 있도록 해주었다.

이렇게 fetch api로 불러온 getMovies(), getTopRatedMovies()를 가져와

MovieCopoment

import { useEffect, useState } from 'react';
import { IMovie } from '../api/movieApi';

interface NowPlayMovieProps {
  fetchFunction: () => Promise<{ results: IMovie[] }>; // fetchFunction은 비동기 함수로 정의
}

export default function MovieComponent({ fetchFunction }: NowPlayMovieProps) {
  const [movies, setMovies] = useState<IMovie[]>([]);

  useEffect(() => {
    const fetchMovies = async () => {
      try {
        const data = await fetchFunction();
        setMovies(data.results);
      } catch (error) {
        console.error('Failed to fetch movies:', error);
      }
    };
    fetchMovies();
  }, [fetchFunction]);

  return (
    <>
      <div className="flex flex-wrap -mx-2 w-full">
        {movies.map((movie) => (
          <div
            key={movie.id}
            className="w-1/4 px-2 mb-6 hover:scale-105 duration-200 transition-transform ease-in-out"
          >
            <img
              src={`https://image.tmdb.org/t/p/w500${movie.poster_path}`}
              alt={movie.title}
              className="rounded-md w-full"
            />
            <div className="flex justify-between items-center font-bold mt-4 mb-2 text-lg">
              <h4 className="truncate">{movie.title}</h4>
            </div>
            <div className="flex justify-between items-center text-sm text-gray-200">
              <div className="flex items-center gap-2 font-bold">
                <h1>⭐️</h1>
                <span className="text-yellow-500">{movie.vote_average}</span>
              </div>
              <span className="text-yellow-500 font-bold">
                {movie.release_date.slice(0, 4)}
              </span>
            </div>
          </div>
        ))}
      </div>
    </>
  );
}

를 생성해서
fetch API를 불러와서 데이터를 뿌려줄 수 있는 movie component를 생성해 주었다.
여기서 확인할 수 있는 것은 ?
-> 어떠한 movie 데이터를 불러와도 컴포넌트를 재사용할 수 있다는 점이다!

App.tsx

...
		<h2 className="text-[36px] font-bold mb-8">Now Play Movie</h2>
          <div className="">
            <MovieComponent fetchFunction={getMovies} />
          </div>

          <h2 className="text-[36px] font-bold mb-8">Top Rated Movie</h2>
          <div className="">
            <MovieComponent fetchFunction={getTopRatedMovies} />
          </div>
...

그리고 App.tsx 에서 컴포넌트를 불러서 사용하면 끝!

강사님은

Api.tsx

const apiUrl = "https://api.themoviedb.org/3/movie";
export const nowPlayingUrl = `${apiUrl}/now_playing`;
export const popularUrl = `${apiUrl}/popular`;
export const upComingUrl = `${apiUrl}/upcoming`;
export const initailData = {
  results: [],
};
export const options = {
  method: "GET",
  headers: {
    accept: "application/json",
    Authorization:
      "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIzZDZjODUwZmVkZDY0YTUwN2U1MWNmYjIzMzVmMzA1YyIsIm5iZiI6MTcyNzQwOTg0Ny42NjgwOTgsInN1YiI6IjYxMjViZDU5OGMzMTU5MDA2Mjk4OTUzNSIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.5_O-IqktGsssq312RHhJMeJhITPtb-FXYalzHTLrgZU",
  },
};

이렇게 options를 통해서 데이터를 불러온 뒤,

App.tsx에서 각 movie의 결과값과, 타입을 지정해 준 뒤

const {
    data: { results: nowPlaying },
    isLoading: isLoadingNowplaying,
    isError: isErrorNowPlaying,
  } = useFetch<MovieDataType>(nowPlayingUrl, initailData, options);

  
  import MovieItem from "./MovieItem";

요런 식으로 movie list를 뿌려주었다.

export default function MovieArea({
  movies,
  title,
}: {
  movies: MovieType[];
  title: string;
}) {
  return (
    <>
      {/* 무비 에어리어 */}
      <article className="bg-black py-10 px-4 xs:px-0">
        <section className="container mx-auto text-white">
          <span className="text-yellow-600">ONLINE STREAMING</span>
          <h2 className="text-[36px] font-bold mb-8">{title}</h2>
          <div className="grid grid-cols-1 xs:grid-cols-2 md:grid-cols-4 gap-6 sm:px-0">
            {movies.map((movie) => (
              <MovieItem key={movie.id} {...movie} />
            ))}
          </div>
        </section>
      </article>
    </>
  );
}

라우터

리액트에서 라우터는 react-router-dom 패키지를 사용해서 처리한다.

라우터 설정

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./assets/css/index.css";

import { createBrowserRouter, RouterProvider } from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    element: <App />,
  },
]);

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

Next.js

npm 초기화

npm init -y

Next.js 패키지 설치

npm install react@latest next@latest react-dom@latest

Package.json

 "start": "next dev",

본 후기는 본 후기는 [유데미x스나이퍼팩토리] 프로젝트 캠프 : Next.js 3기 과정(B-log) 리뷰로 작성 되었습니다.
#유데미 #udemy #웅진씽크빅 #스나이퍼팩토리 #인사이드아웃 #미래내일일경험 #프로젝트캠프 #부트캠프 #React #리액트프로젝트 #프론트엔드개발자양성과정 #개발자교육과정

profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글