부캠/TypeScript&Next

[NEXT] 마지막 갠 과제에 쓴 거 정리 (2)

FS29 2024. 12. 19. 17:57

1. fetchChampionRotation [TypeScript: 제네릭(Generic), 타입 지정]

async function fetchChampionRotation(): Promise<ChampionRotation> {

 

fetchChampionRotation함수가 반환하는 값의 타입을 제네릭을 사용하여 ChampionRotation라고 명시해줬다.

마치, 이 함수가 반환하는 값이 ChampionRotation타입의 데이터로 이루어진 Promise야!라고 말하는 거와 같다.

 

여기서 Promise를 쓴 이유는, 잠시 후 데이터를 반환할게라고 약속한는 형태로 동작하기 때문이다. 즉, 비동기 작업을 반환하는 의미다.

 


2. API Route

 

const response = await fetch("/api/rotation");

 

/page/api 폴더 안에 작성된 파일들이 자동으로 api 엔드포인트가 된다.

예를들어 pages/api/rotation.ts파일이 있으면, 위 코드처럼 작성하면 된다. 이때, 임포트는 불필요하다. 넥스트가 내부적으로 이 경로를 자동으로 처리하기 때문에 파일경로와 url경로가 매핑되어 별도의 임포트없이 사용 가능하다.

 

// src/app/api/rotation/route.ts
import { NextResponse } from "next/server";

export async function GET() {
  const data = { message: "Hello, API Route!" };
  return NextResponse.json(data);
}
// 위 코드처럼 작성하면 /api/rotation에서 GET요청을 처리할 수 있다.

 

 


3. useQuery

 

내가 가장 헷갈렸던 게 탄스택이다. 분명히 리액트에서는 화살표 함수를 이용하였는데, 넥스트에서는 모양새가 살짝 달랐다.

const {
  data: rotationData,
  isPending,
  isError,
} = useQuery({
  queryKey: ["championRotation"], // 이 쿼리의 고유 식별자
  queryFn: async () => {
    const response = await fetch("/api/rotation"); // 데이터를 가져오는 비동기 함수
    return response.json();
  },
});

 

위 코드는 리액트로 바꿔본 코드이다. queryFn에 비동기 함수를 화살표함수를 이용하여 처리하고 있다.

async function fetchChampionRotation() {
  const response = await fetch("/api/rotation");
  if (!response.ok) throw new Error("Failed to fetch rotation data");
  return response.json();
}

useQuery({
  queryKey: ["championRotation"],
  queryFn: fetchChampionRotation, // 함수 참조
});

 

위 코드는 넥스트로 바꿔본 코드이다. 비동기 함수명을 그대로 넣어주고있다.

 

 

사실, 넥스트에서 화살표 함수도 가능한데, 프로젝트가 커질수록 동일한 로직을 여러 곳에서 사용할 일이 생기기 때문에 함수 분리가 더 편하다. 

 

 

 

 

위 코드는 간결해서 재사용성이 좋은 건지 알 수 없다. 그래서 코드를 가져와봤다.

 

 

 

 

1) API 호출 로직을 분리

// src/utils/riotApi.ts
export async function fetchChampionRotation() {
  const response = await fetch("https://ddragon.leagueoflegends.com/api/rotation");
  if (!response.ok) {
    throw new Error("Failed to fetch champion rotation data");
  }
  return response.json();
}

 

 

 

2) 클라이언트 컴포넌트에서 재사용

// src/app/rotation/page.tsx
"use client";

import { useQuery } from "@tanstack/react-query";
import { fetchChampionRotation } from "@/utils/riotApi";

export default function RotationClientComponent() {
  const {
    data: rotationData,
    isPending: isLoading,
    isError,
  } = useQuery({
    queryKey: ["championRotation"],
    queryFn: fetchChampionRotation,
  });

  if (isLoading) return <div>Loading...</div>;
  if (isError) return <div>Error loading rotation data</div>;

  return (
    <ul>
      {rotationData.freeChampionIds.map((id: number) => (
        <li key={id}>Champion ID: {id}</li>
      ))}
    </ul>
  );
}

 

 

 

 

3) 서버 컴포넌트에서 재사용

// src/app/server-rotation/page.tsx
import { fetchChampionRotation } from "@/utils/riotApi";

export default async function RotationServerComponent() {
  const rotationData = await fetchChampionRotation();

  return (
    <ul>
      {rotationData.freeChampionIds.map((id: number) => (
        <li key={id}>Champion ID: {id}</li>
      ))}
    </ul>
  );
}

 

 

4) 다른 컴포넌트에서 재사용

// src/pages/rotation-ssr.tsx
import { fetchChampionRotation } from "@/utils/riotApi";

export async function getServerSideProps() {
  const rotationData = await fetchChampionRotation();
  return { props: { rotationData } };
}

export default function RotationSSR({ rotationData }: { rotationData: any }) {
  return (
    <ul>
      {rotationData.freeChampionIds.map((id: number) => (
        <li key={id}>Champion ID: {id}</li>
      ))}
    </ul>
  );
}

 

 

 

 

 

 

 

 

 

갠플보다 팀플이 더 좋음 ^-^)b

 

'부캠 > TypeScript&Next' 카테고리의 다른 글

[NEXT]Basic zoom (2) middleware & supabase ssr  (0) 2024.12.21
[NEXT]Basic zoom (1) route handler  (0) 2024.12.21
[NEXT] 마지막 갠 과제에 쓴 거 정리 (1)  (1) 2024.12.18
[NEXT]주요렌더링  (4) 2024.12.09
[TYPESCRIPT]1주차  (2) 2024.12.07