React 에서 Next.js 15버전으로 마이그레이션하기 #1

Leesu·2025년 5월 15일
0

[TIL] : Today I Learned

목록 보기
25/25

React 18 + JavaScript로 만든 프로젝트를 Next.js 15 + TypeScript로 옮기는 작업을 시작했다.
이런 결정을 내리게 된 데에는 몇 가지 이유가 있는데,

우선 첫번째로 ReactVite와 함께 이미 두세 번 정도의 프로젝트를 통해 꽤 익숙해진 상태였다. 하지만 Next.js는 공부는 해놓았으나 정작 실전, 특히 큰 규모의 프로젝트에서 제대로 활용해본 경험이 부족했다. 아무래도 아는 것과 실제로 적용해보는 것은 차이가 크니까..

두번째. SEO 때문이었다. react-helmet 라이브러리를 사용해도 SEO 에 한계가 있기에 Next.js가 필요하겠다. 결정.

세번째. 언제까지 React 만 할 줄 알거야?. 그래서 결정!

물론 두 프레임워크 모두 사용해본 경험은 있지만, 이렇게 기존 프로젝트를 마이그레이션하는 것은 처음이라 솔직히 조금 긴장된다. 쉬운 일은 아니니까...
하지만 이 과정을 자세히 기록해두면 나중에 비슷한 상황에서 도움이 될 것 같아서, 앞으로 마이그레이션하면서 겪는 일들을 상세히 남겨볼 예정이다.

🔥 1. 마이그레이션 계획 세우기

일단 전체 마이그레이션을 한 번에 진행하기보다는 단계적으로 접근하기로 했다.
처음에는 Next.js 프로젝트를 새로 만들고, 기존 React 코드를 조금씩 옮겨가는 방식을 택했다.

무작정 코드를 옮기는 것보다 구조를 제대로 설계하는 게 중요하다고 생각했기 때문이다.

그래서 이번 #1에서는 구조를 만들고 왜 이런 구조를 만들었는지 적어놓으려한다.

🔥 2. Next.js 프로젝트 초기화 & 세팅하기

먼저 Next.js 15버전과 TypeScript를 사용하는 새 프로젝트를 생성했다.
그리고 설정은 아래처럼 했다.

✅ TypeScript 사용
✅ ESLint 사용
✅ src/ 디렉토리 사용
✅ App Router 사용

그리고 프로젝트를 구성할 큰 라이브러리들은 아래와 같다.

1. Material UI

  • 먼저, 나의 짝꿍... 애증의 Material UI.
    이 라이브러리를 선택한 이유는 항상 두 가지 이다.
    디자인 시스템 없이 빠르게 화면을 구성해야 하는 나에게는 안성 맞춤이여서,
    react-hook-form 이랑 연계해서 사용하기 좋아서이다.
    Ant 나 차크라 ui 로 바꾸는 것도 고민해 보았는데 이건 시간이 더 주어지면 학습해서 바꿔볼 예정이다.ㅎ

2. Redux-toolkit

  • 사실은 recoil 도 사용해봤기에 이번 기회에 한번 바꿔볼까 고민을 안해본건 아니다.
    그런데, 아직은 생태계와 커뮤니티가 Redux-toolkit 이 recoil 보다는 크고 안정적이므로,
    그대로 리덕스를 데려가기로 했다.

3. Axios vs Fetch

  • 이건 아직 못정했다.
    인터셉터 기능이 유용해서 Axios 를 아주 잘써왔었는데,
    Next.jsAxios 보다 Fetch 가 이미 Next.js의 렌더링 구조와 긴밀하게 통합되어 있는 것 같아서 다음 #2 편을 적을 때 정해서 도입해볼 예정이다!

4. React-hook-form

  • 스키마 유효성 검증은 너로 끝낸다!

🔥 3. 프로젝트 구조 설계하기

Next.js App Router를 사용하기로 했기 때문에, 폴더 구조를 다음과 같이 계획했다:

src/
├── app/                         # Next.js App Router 파일들
│   ├── layout.tsx               # 루트 레이아웃
│   ├── page.tsx                 # 메인 페이지
│   └── (dynamic)/               # 라우트 그룹
│       ├── dashboard/           # 대시보드 페이지
│       ├── profile/             # 프로필 페이지
│       └── ...
│
├── components/                  # 모든 컴포넌트
│   ├── atoms/                   # 버튼 등 가장 작은 단위의 컴포넌트들
│   │   ├── Button/
│   │   └── ...
│   │
│   ├── forms/                   # mui contorl 공용 컴포넌트
│   │   ├── formProvieder.tsx
│   │   └── ...
│   │
│   ├── layout/                  # 레이아웃 관련 컴포넌트
│   │   ├── Header/
│   │   ├── Footer/
│   │   ├── Sidebar/
│   │   └── ...
│   │
│   └── features/                # 특정 기능에 관련된 컴포넌트
│       ├── auth/
│       ├── dashboard/
│       └── ...
│
├── lib/                         # 유틸리티 함수 및 API
│   ├── constants.ts             # 공통 상수 정의 파일
│   ├── api/                     # API 관련 함수
│   ├── redux/                   # Redux 관련 파일
│   ├── utils/                   # 유틸리티 함수
│   └── hooks/                   # 커스텀 훅
│       ├── useAuth.ts
│       └── ...
│
├── styles/                      # 스타일 관련 파일
│   ├── globalStyles.tsx         # 전역 스타일 프로바이더
│   ├── theme.ts                 # MUI Joy 테마 설정
│   └── ...
│
└── types/                       # 타입 정의
    ├── api.types.ts
    ├── user.types.ts
    └── ...

react 를 사용할 때는 도메인별로 폴더를 나눠서 작업하고,
가끔 도메인이 애매한 공용 컴포넌트들은 share 폴더에 넣어놓고 썼었는데,
그 안에서도 나누지 않아서 가끔 스크롤로 엄청 뒤졌더랜다.... 그래서 깨알 Atomic design 사용...

🤔 Atom 이란?
Atom은 더 이상 분해할 수 없는 가장 작은 컴포넌트입니다. 마치 화학에서 원자가 물질의 기본 단위인 것처럼, 디자인 시스템에서 Atom은 UI의 기본 단위라고 생각하면 된다.
버튼, 입력창, 레이블, 체크박스 등 기본 HTML 요소부터,
색상, 글꼴, 애니메이션, 레이아웃 등 추상적 요소도 해당될 수 있다!

특징으로는 더 이상 분해할 수 없고
단순하고
재사용성이 높고
다른 컴포넌트에 의존하지 않도록 독립적이여야한다.

atom/ 폴더 외에 forms/ 폴더가 따로 있는 이유는
forms/ 폴더 안에 들어가는 input 등의 경우 순수한 atom 단위가 아니기 때문이다.

muireact-hook-form 을 사용해서 만든 input 이므로
react-hook-form 의 컨트롤러를 사용하여 폼 상태 관리와 결합되어 있기 때문이다.

그래서 엄밀히 말하자면 Atom 보다는 Molecule에 가깝기에,
따로 폴더를 만들었다.


우선 이렇게 초기 작업을 마쳤다. 다음 편에는 axios 와 fetch 중에 어떤걸 사용할지, 사용한다면 왜 사용해야할까 등을 고민해서 적어봐야겠다.. ~!

🚩 참고 문서

0개의 댓글