아랄라랄라
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] 초보의 관리자 페이지 만들기 시작기

2026. 4. 28. 09:31

 

설치부터 레이아웃, 목록/상세/수정/등록 흐름까지

 

이번에 관리자 페이지 작업을 하게 되면서 Next.js를 처음 제대로 만져보게 됐다.
원래는 React를 아주 조금 알고 있었고, HTML/CSS는 익숙한 편이지만 JavaScript와 Next.js는 거의 초보 수준이었다.

 

처음에는 “이걸 다 새로 만들어야 하나?”라는 막막함이 있었는데,
실제로 하나씩 부딪혀보니 Next.js는 폴더 구조와 페이지 흐름을 익히는 것부터 시작하는 게 중요하다는 걸 느꼈다.

 

이번 글은 내가 로컬에 Next.js를 설치하고, 관리자 페이지의 기본 흐름인
목록 → 상세 → 수정 → 등록
구조를 만드는 과정까지 정리한 기록이다.

 

 


 

 

1. 로컬 환경 세팅

먼저 Node와 npm 버전을 확인했다.

node -v
npm -v
 
 

내 환경은 아래와 같았다.

  • Node.js v20.19.2
  • npm 10.8.2

버전 자체는 충분했지만, 설치 과정에서 바로 문제가 생겼다.

 

설치 중 만난 문제: ECONNRESET

create-next-app 실행 시 아래와 같은 에러가 발생했다.

npm error code ECONNRESET
npm error network request to https://registry.npmjs.org/create-next-app failed
 

처음에는 npm 설정 문제인 줄 알았지만, 확인해보니 회사 내부망 이슈였다.
결국 네트워크 문제를 해결한 뒤 다시 설치를 진행했고, 정상적으로 Next.js 프로젝트를 생성할 수 있었다.

 

 


 

 

 

2. Next.js 프로젝트 생성

설치는 아래 명령어로 진행했다.

npx create-next-app@latest admin-next
 

옵션은 다음처럼 선택했다.

  • TypeScript: Yes
  • ESLint: Yes
  • Tailwind CSS: No
  • src directory: Yes
  • App Router: Yes
  • Turbopack: Yes

내 경우에는 Bootstrap 기반 UI 감각을 유지한 채 Next.js 구조를 익히는 것이 목적이었기 때문에, Tailwind는 일단 제외했다.

설치가 끝난 뒤 아래 명령어로 실행까지 확인했다.

cd admin-next
npm run dev
 

 

 


 

 

 

3. 처음 이해한 Next.js 기본 구조

프로젝트를 실행한 뒤 가장 먼저 본 파일은 아래 3개였다.

  • src/app/page.tsx
  • src/app/layout.tsx
  • src/app/globals.css

이때 가장 먼저 이해한 개념은 다음과 같다.

  • page.tsx → 실제 페이지 화면
  • layout.tsx → 공통 레이아웃
  • globals.css → 전역 스타일

그리고 Next.js App Router에서는 폴더 구조가 곧 URL 구조가 된다는 점이 굉장히 중요했다.

 

예를 들어,

src/app/admin/dashboard/page.tsx
 

를 만들면 바로

 

/admin/dashboard
 

경로가 된다.

 

이 구조가 익숙해지기 시작하면서 Next.js가 조금씩 이해되기 시작했다.

 

 


 

 

 

4. 첫 관리자 페이지 만들기

가장 먼저 만든 페이지는 관리자 대시보드였다.

export default function DashboardPage() {
    return (
        <main>
            <h1>관리자 대시보드</h1>
            <p>첫 관리자 페이지입니다.</p>
        </main>
    )
}

 

이후 src/app/admin/layout.tsx를 만들고, 관리자 공통 레이아웃인 사이드바 + 헤더 + 본문 영역 구조를 잡았다.

 

이 단계에서 알게 된 점은, 관리자 페이지는 개별 화면보다 먼저 공통 프레임을 잡는 것이 훨씬 중요하다는 점이었다.

 

 


 

 

 

5. a href 대신 Link 사용하기

처음엔 사이드바 링크를 일반 <a href="">로 넣었는데, Next.js에서는 Link를 사용하는 게 맞다는 걸 알게 됐다.

 

다만 여기서 작은 실수를 했다.

import Link from 'next/Link'
 

처럼 대문자 L로 import를 해서 에러가 발생했다.

 

정답은 아래였다.

import Link from 'next/link'
 

소문자 경로를 써야 한다는 점을 제대로 기억하게 된 계기였다.

 

 

 

 


 

 

 

6. 회원 목록 페이지 만들기

그다음에는 관리자 페이지에서 가장 기본이 되는 회원 목록 페이지를 만들었다.

 
const users = [
  { id: 1, name: '홍길동', email: 'hong@test.com', status: '활성' },
  { id: 2, name: '김민지', email: 'kim@test.com', status: '비활성' },
  { id: 3, name: '이준호', email: 'lee@test.com', status: '활성' },
]

 

이 배열을 기준으로 테이블을 렌더링하면서 아래 개념들을 같이 익혔다.

  • 배열 데이터 만들기
  • map()으로 반복 렌더링
  • key 사용
  • 기본적인 테이블 UI 구성

이 시점부터 “관리자 페이지를 만들고 있다”는 느낌이 확실히 들기 시작했다.

 

 


 

 

 

 

7. 상세 페이지와 동적 라우팅 이해하기

회원 목록에서 이름을 클릭하면 상세 페이지로 이동하도록 만들었다.

 

예를 들어 아래 구조를 만들면,

src/app/admin/users/[id]/page.tsx
 

URL의 id 값을 받아 상세 페이지를 렌더링할 수 있다.

 

이 과정에서 처음엔 “페이지에 id 말고 다른 값도 넘길 수 있나?”라는 궁금증이 생겼고, 이를 통해 아래 개념 차이를 정리하게 됐다.

  • props → 컴포넌트끼리 값 전달
  • params → URL 경로값
  • searchParams → URL 쿼리값

즉, 상세 페이지에서 받는 id는 props가 아니라 URL의 동적 경로값이었다.

 

 


 

 

 

8. 수정 페이지 만들기: /admin/users/1/edit

상세 페이지 아래에 수정하기 버튼을 붙이고, /admin/users/[id]/edit/page.tsx 구조로 수정 페이지를 만들었다.

 

이 단계에서 처음엔 단순히 입력창만 띄워보는 수준이었지만, 곧 “진짜 입력 가능한 수정 페이지”가 필요해졌다.

 

여기서 핵심은 두 가지였다.

 

A. 뒤로가기 버튼 붙이기

이건 페이지 이동 흐름을 만드는 단계였다.

  • 상세로 돌아가기
  • 목록으로 돌아가기

즉, 내비게이션의 문제였다.

 

B. useState로 진짜 수정 가능하게 만들기

이건 입력 기능을 만드는 단계였다.

  • 이름 수정
  • 이메일 수정
  • 상태 변경

즉, 폼 상태 관리의 문제였다.

 

이 둘의 차이를 정리하면서, 수정 페이지에는 이동 기능과 입력 기능이 모두 필요하다는 걸 이해하게 됐다.

 

 

 


 

 

9. useParams와 useState의 차이

수정 페이지를 만들다가 처음 헷갈렸던 부분이 바로 이것이었다.

 

처음엔 “진짜 입력 가능하게 만드는 것”이 useParams를 쓰는 건가 싶었는데, 정리해보면 둘은 역할이 완전히 달랐다.

  • useParams → URL에서 어떤 회원인지 확인하는 용도
  • useState → 입력값을 현재 상태로 저장하는 용도

즉,

  • useParams는 “누구를 수정하는지”
  • useState는 “무엇을 어떻게 바꾸는지”

를 담당한다.

 

이 차이를 이해하고 나니 수정 페이지 흐름이 훨씬 선명해졌다.

 

 


 

 

 

10. 저장 후 상세 페이지로 이동하기

수정 페이지에서 저장 버튼을 누르면 단순히 alert만 띄우는 게 아니라, 저장 후 상세 페이지로 이동하도록 만들었다.

 

여기서 사용한 것은 useRouter였다.

const router = useRouter()

router.push(`/admin/users/${id}`)
 

이걸 통해 알게 된 것은,

  • Link → 사용자가 클릭해서 이동
  • router.push() → 코드로 자동 이동

이라는 차이였다.

 

이때부터 단순히 화면을 만드는 것이 아니라 관리자 페이지 흐름을 제어한다는 느낌을 받았다.

 

 


 

 

 

11. 회원 등록 페이지 만들기

다음으로는 /admin/users/new 경로의 회원 등록 페이지를 만들었다.

수정 페이지와 등록 페이지는 구조가 비슷하지만 차이도 분명했다.

 

수정 페이지

  • 기존 데이터가 들어있음
  • 특정 id가 있음
  • 저장하면 수정

등록 페이지

  • 입력값이 비어있음
  • 아직 id가 없음
  • 저장하면 새 데이터 생성

즉, 화면 구조는 비슷하지만 목적이 다르다는 걸 이해하게 됐다.

 

 

 


 

 

 

12. 더미데이터를 파일로 분리하기

처음에는 users 배열을 목록 페이지 안에 직접 두고 썼다.
하지만 상세 페이지와 수정 페이지에서도 같은 데이터를 써야 하다 보니, 중복이 생기기 시작했다.

 

그래서 아래 파일을 만들었다.

src/lib/dummy-data.ts
 

 

그리고 데이터를 분리했다.

export const users = [
    { id: 1, name: '홍길동', email: 'hong@test.com', status: '활성' },
    { id: 2, name: '김민지', email: 'kim@test.com', status: '비활성' },
    { id: 3, name: '이준호', email: 'lee@test.com', status: '활성' },
]
 

이렇게 하니 목록, 상세, 수정 페이지가 같은 데이터를 참조할 수 있게 됐고,
페이지 코드도 훨씬 가벼워졌다.

 

 


 

 

 

13. src 구조와 path alias 문제

중간에 src 폴더를 구성하면서 또 하나 막힌 부분이 있었다.

 

다음과 같은 에러가 발생했다.

Module not found: Can't resolve '@/lib/dummy-data'
 

원인을 확인해보니 tsconfig.json의 path 설정에 src가 빠져 있었다.

 

해결은 아래처럼 했다.

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
        	"@/*": ["./src/*"]
        }
    }
}
 

즉, @ 별칭이 src를 바라보도록 설정해야 했다.

 

이 과정에서 알게 된 것은, 폴더 구조를 바꾸면 import alias 설정도 함께 맞춰줘야 한다는 점이었다.

 

 


 

 

 

14. 등록/수정 폼을 공통 컴포넌트로 분리하기

등록 페이지와 수정 페이지를 만들고 나니, 이름 input / 이메일 input / 상태 select / 버튼 구조가 거의 똑같다는 걸 알게 됐다.

 

그래서 아래 공통 컴포넌트를 만들었다.

src/components/admin/users/user-form.tsx
 

이후

  • 등록 페이지는 빈 초기값
  • 수정 페이지는 기존 회원 데이터 초기값

을 넘겨서 같은 폼을 재사용하도록 구조를 정리했다.

 

이 단계에서 특히 크게 느낀 건, “작동하는 코드”와 “정리된 코드”는 다르다는 점이었다.

 

처음엔 페이지 안에 전부 적는 게 쉬웠지만, 조금만 흐름이 늘어나도 공통 컴포넌트 분리가 필요해졌다.

 

 


 

 

 

15. 이번 과정을 통해 느낀 점

이번 작업을 하면서 느낀 가장 큰 점은,

Next.js를 처음 배울 때 중요한 건 복잡한 개념보다 구조와 흐름을 직접 만들어보는 것이라는 점이다.

 

특히 아래 흐름을 손으로 만들어보면서 많이 익혔다.

  • /admin/users → 목록
  • /admin/users/[id] → 상세
  • /admin/users/[id]/edit → 수정
  • /admin/users/new → 등록

그리고 이 과정에서 자연스럽게 익힌 것들은 다음과 같다.

  • App Router 구조
  • layout.tsx와 page.tsx
  • Link
  • useParams
  • useState
  • useRouter
  • 더미데이터 분리
  • 공통 폼 컴포넌트 분리
  • tsconfig path alias 설정

 

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

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

[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.24
[Next.js] 공부 시작 전, 내 현재 수준과 학습 방향 정리  (0) 2026.04.21
[리액트] Hooks 알아보기  (0) 2023.06.08

티스토리툴바