아랄라랄라
R 스토리
아랄라랄라
전체 방문자
오늘
어제
  • All (207) N
    • Web (152) N
      • Markup | WEB (9)
      • Styles (45)
      • javascript (32)
      • jquery (28)
      • vue (16)
      • react (17) N
      • more (5)
    • IT (32)
      • CS (3)
      • git hub (5)
      • UI | UX (18)
      • more (6)
    • ETC (23) N
      • 이슈노트 (13) N
      • 스터디 (10)
      • 아랄라 ☞☜ (0)
      • JOB🛠 (0)

인기 글

반응형
hELLO · Designed By 정상우.
아랄라랄라

R 스토리

Web/react

[Next.js] Next.js + TypeScript + Tailwind CSS 관리자 페이지 만들기 2

2026. 5. 14. 10:33

프로젝트 시작

생성

npx create-next-app@latest

 

 

 

선택한 옵션

  • TypeScript
  • App Router
  • Tailwind CSS
  • src 구조

 

 

처음 만난 에러

Missing <html> and <body> tags in the root layout

처음 실행하자마자 만난 에러.

 

원인

App Router에서는:

layout.tsx가 HTML 뼈대 역할

을 한다.

 

그래서 반드시:

<html>
<body>

태그가 필요했다.

 

 

수정

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ko">
      <body>{children}</body>
    </html>
  );
}

 

 

 

 

App Router 구조 이해하기

예전 React처럼:

“컴포넌트만 만들면 되는 구조”

가 아니라,

폴더 구조 자체가 라우팅이었다.

예시

app/
 ├─ admin/
 │   ├─ ads/
 │   │   ├─ page.tsx

 

의미

/admin/ads

URL이 자동 생성된다.

 

 

 

관리자 페이지 만들기 시작

처음 만든 건 광고 목록 페이지였다.

 

 

 

더미 데이터 만들기

dummy-data.ts

export type AdStatus = "진행중" | "대기" | "종료";

export type Ad = {
    id: number;
    title: string;
    position: string;
    status: AdStatus;
    startDate: string;
    endDate: string;
};

export const ads: Ad[] = [
    {
        id: 1,
        title: "메인 상단 배너 광고",
        position: "홈 메인 상단",
        status: "진행중",
        startDate: "2026-05-01",
        endDate: "2026-05-31",
    },
];

 

 

 

여기서 처음 느낀 TypeScript의 장점

status 값을 마음대로 못 넣게 막아준다

 

예:

status: "완료" ❌

 

 

 

 

TailwindCSS 사용

처음엔 클래스가 너무 길어 보였는데,

점점:

“HTML 안에서 바로 스타일 조합”

하는 방식이 엄청 빠르다는 걸 느꼈다.

 

반응형도 쉽게 가능

<div className="flex flex-col gap-4 sm:flex-row">

 

 

의미

모바일:

세로 배치

 

sm 이상:

가로 배치

 

 

 

 

상세 페이지 만들기

다음은 동적 라우팅.

구조:

app/admin/ads/[id]/page.tsx

 

 

 

 

여기서 이해한 개념

[id] = URL 파라미터

 

 

 

 

예시

/admin/ads/1
/admin/ads/2

 

 

 

 

처음 만난 params 에러

에러

params is a Promise

 

원인

Next.js App Router 최신 버전에서는:

params가 Promise 형태일 수 있다

 

해결

type Props = {
    params: Promise<{
        id: string;
    }>;
};

export default async function Page({ params }: Props) {
    const { id } = await params;
}

 

 

여기서 이해한 핵심

App Router는 전체적으로:

async 기반 구조

라는 것.

 

 

 

Server Component vs Client Component

여기서 가장 많이 헷갈렸다.

 

처음엔 이렇게 생각했다

“수정 페이지도 서버 데이터 쓰니까 Server Component 아닌가?”

 

 

하지만 핵심 차이는 이것이었다

Server Component

데이터 조회

 

 

Client Component

브라우저 인터랙션

 

 

 

 

예시

Server Component 가능

  • 데이터 가져오기
  • DB 조회
  • 페이지 렌더링

 

Client Component 필요

  • useState
  • onClick
  • input 입력
  • 모달
  • 이벤트 처리

 

여기서 배운 핵심

“브라우저에서 동작하면 Client”

 

 

use client 에러도 경험

처음엔:

use strict

를 써놓고 왜 안 되는지 한참 헤맸다 😇

 

실제로 필요한 건

"use client";

 

 

수정 페이지 만들기

수정 페이지에서는:

  • input
  • select
  • state

를 사용했다.

 

여기서 배운 것

폼 = 거의 Client Component

 

 

TypeScript select 이벤트도 처음 경험

onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
    setStatus(e.currentTarget.value as AdStatus);
}}

 

 

처음 느낌

“왜 이렇게 길어?”

 

 

그런데 이해하고 보니

TypeScript가:

“이 이벤트가 select 이벤트라는 걸 명확하게 알려주는 것”

이었다.

 

 

 

삭제 모달 만들기

다음은 관리자 페이지에서 자주 쓰는 기능인:

삭제 버튼 + 확인 모달

 

 

구조 분리

[id]/page.tsx
└── DeleteModal.tsx

 

 

왜 분리했나?

상세 페이지는:

async function

형태의 Server Component였고,

 

모달은:

  • useState
  • onClick

이 필요했기 때문.

 

여기서 이해한 개념

Server Component 안에
Client Component를 넣을 수 있다

 

 

API Route 만들기

이번엔 진짜 CRUD 느낌이 나기 시작했다.

구조

src/app/api/ads/[id]/route.ts

 

App Router에서 API 만드는 법

route.ts = API endpoint

 

DELETE API 작성

export async function DELETE() {
}

 

fetch 요청

await fetch(`/api/ads/${adId}`, {
    method: "DELETE",
});

 

그런데 DELETE가 안 됐다

GET은 되는데 DELETE만:

404 Not Found

 

 

 

진짜 원인

문제는 params 타입이었다.

잘못된 코드

{ params }: { params: { id: string } }

 

해결 코드

{ params }: { params: Promise<{ id: string }> }

const { id } = await params;

 

여기서 배운 핵심

App Router 최신 구조에서는:

params도 async 흐름일 수 있다

 

Turbopack도 처음 이해하게 됨

에러 로그에 계속 보이던:

turbopack

 

Turbopack이란?

쉽게 말하면:

Next.js 개발 서버를 빠르게 돌려주는 최신 엔진

 

장점

  • 빠른 실행
  • 빠른 HMR
  • Next.js 최적화

단점

가끔:

  • route.ts 인식 문제
  • 캐시 문제
  • POST/DELETE 이상 동작

같은 이슈가 있음.

 

 

그래서 실무에서는

문제 생기면:

rm -rf .next
npm run dev

하거나,

next dev --no-turbo

로 잠시 끄기도 한다.

 

 

 

이번 프로젝트로 이해한 것들

✔ App Router 구조

폴더 구조 자체가 라우팅

 

 

✔ Server vs Client

조회는 서버
인터랙션은 클라이언트

 

 

✔ CRUD 흐름

브라우저 → API → 데이터 처리

 

 

✔ async 기반 구조

params도 Promise일 수 있다

 

 

 

 

느낀 점

처음엔:

“Next.js 너무 어려운데?”

싶었는데,

 

관리자 페이지를 실제로 만들면서 배우니까:

  • 왜 Server Component가 필요한지
  • 왜 Client Component가 필요한지
  • 왜 TypeScript를 쓰는지
  • 왜 App Router가 async 기반인지

조금씩 연결되기 시작했다.

특히 단순히 문법만 보는 게 아니라:

“실제 기능을 만들며 배우는 방식”

 

이 훨씬 이해가 잘 됐다 😄

728x90
저작자표시 (새창열림)

'Web > react' 카테고리의 다른 글

[Next.js] Next.js App Router 경계 정리표  (0) 2026.05.18
[Next.js] Server vs Client Component 완전 정리  (0) 2026.05.08
[Next.js] Next.js + TypeScript + Tailwind CSS 관리자 페이지 만들기 1  (1) 2026.05.08
[Next.js] 초보의 관리자 페이지 만들기 시작기  (0) 2026.04.28
[Next.js] 프로젝트 시작하기  (0) 2026.04.24

티스토리툴바