본문 바로가기

카테고리 없음

[React] 확장 가능한 React 프로젝트 구조 설계하기

반응형

 

React 프로젝트를 시작할 때 가장 중요한 결정 중 하나는 프로젝트 구조를 어떻게 설계할 것인가입니다. 잘 설계된 프로젝트 구조는 코드의 가독성을 높이고, 유지보수를 용이하게 하며, 팀 협업을 원활하게 만듭니다. 이 블로그에서는 확장 가능한 React 프로젝트 구조를 설계하는 방법에 대해 자세히 알아보겠습니다.

1. 기본 디렉토리 구조

먼저, 기본적인 디렉토리 구조부터 살펴보겠습니다.

my-react-project/
├── public/
├── src/
│   ├── components/
│   ├── pages/
│   ├── hooks/
│   ├── contexts/
│   ├── services/
│   ├── utils/
│   ├── styles/
│   ├── assets/
│   ├── App.js
│   └── index.js
├── package.json
└── README.md

각 디렉토리의 역할을 살펴보겠습니다:

  • public/: 정적 파일들을 저장합니다. (예: index.html, favicon.ico)
  • src/: 소스 코드가 위치하는 메인 디렉터리입니다.
    • components/: 재사용 가능한 React 컴포넌트들을 저장합니다.
    • pages/: 라우트에 해당하는 페이지 컴포넌트들을 저장합니다.
    • hooks/: 커스텀 React 훅들을 저장합니다.
    • contexts/: React Context API를 사용한 상태 관리 파일들을 저장합니다.
    • services/: API 호출 등 외부 서비스와의 통신을 담당하는 파일들을 저장합니다.
    • utils/: 유틸리티 함수들을 저장합니다.
    • styles/: 전역 스타일 파일들을 저장합니다.
    • assets/: 이미지, 폰트 등의 자산 파일들을 저장합니다.

이러한 기본 구조는 프로젝트의 규모가 작을 때는 충분할 수 있지만, 프로젝트가 커지면 더 세분화된 구조가 필요합니다.

2. 컴포넌트 구조화

컴포넌트는 React 애플리케이션의 핵심입니다. 컴포넌트를 효과적으로 구조화하는 것이 중요합니다.

2.1 아토믹 디자인 적용

아토믹 디자인 원칙을 적용하여 컴포넌트를 구조화할 수 있습니다:

src/
└── components/
    ├── atoms/
    │   ├── Button/
    │   └── Input/
    ├── molecules/
    │   └── SearchBar/
    ├── organisms/
    │   └── Header/
    └── templates/
        └── HomeTemplate/
  • atoms/: 버튼, 입력 필드 등 가장 기본적인 UI 요소들
  • molecules/: atoms를 조합한 좀 더 복잡한 UI 요소들
  • organisms/: molecules와 atoms를 조합한 더 큰 단위의 UI 섹션
  • templates/: 전체 페이지의 레이아웃을 정의

이렇게 구조화하면 컴포넌트의 재사용성과 일관성을 높일 수 있습니다.

2.2 컴포넌트 파일 구조

각 컴포넌트는 다음과 같은 구조를 가질 수 있습니다:

Button/
├── Button.js
├── Button.test.js
├── Button.module.css
└── index.js
  • Button.js: 컴포넌트의 주 로직
  • Button.test.js: 컴포넌트 테스트 파일
  • Button.module.css: 컴포넌트 스타일 (CSS 모듈 사용)
  • index.js: 컴포넌트를 외부로 내보내는 파일

이렇게 구조화하면 각 컴포넌트와 관련된 모든 파일들을 한 곳에서 관리할 수 있습니다.

3. 상태 관리

프로젝트의 규모가 커지면 효과적인 상태 관리가 필수적입니다.

3.1 Context API 사용

간단한 상태 관리는 React의 Context API를 사용할 수 있습니다:

src/
└── contexts/
    ├── AuthContext.js
    └── ThemeContext.js

예를 들어, AuthContext.js는 다음과 같이 구현할 수 있습니다:

import React, { createContext, useState, useContext } from 'react';

const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  const login = (userData) => {
    setUser(userData);
  };

  const logout = () => {
    setUser(null);
  };

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => useContext(AuthContext);

3.2 Redux 사용

더 복잡한 상태 관리가 필요한 경우 Redux를 사용할 수 있습니다:

src/
└── store/
    ├── actions/
    ├── reducers/
    ├── selectors/
    └── index.js

4. API 통신

API 통신을 위한 구조도 중요합니다:

src/
└── services/
    ├── api.js
    ├── auth.service.js
    └── user.service.js

api.js에서는 axios 인스턴스를 생성하고, 각 서비스 파일에서 이를 사용하여 API 호출을 구현합니다:

// api.js
import axios from 'axios';

const api = axios.create({
  baseURL: process.env.REACT_APP_API_URL,
});

export default api;

// user.service.js
import api from './api';

export const getUserProfile = (userId) => api.get(`/users/${userId}`);
export const updateUserProfile = (userId, data) => api.put(`/users/${userId}`, data);

5. 라우팅

라우팅 구조도 확장 가능하게 설계해야 합니다:

src/
├── pages/
│   ├── Home/
│   ├── Profile/
│   └── Settings/
└── routes/
    ├── PrivateRoute.js
    └── index.js

routes/index.js에서 전체 라우팅 구조를 정의합니다:

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import PrivateRoute from './PrivateRoute';
import Home from '../pages/Home';
import Profile from '../pages/Profile';
import Settings from '../pages/Settings';

const Routes = () => (
  <Router>
    <Switch>
      <Route exact path="/" component={Home} />
      <PrivateRoute path="/profile" component={Profile} />
      <PrivateRoute path="/settings" component={Settings} />
    </Switch>
  </Router>
);

export default Routes;

6. 환경 설정

다양한 환경(개발, 스테이징, 프로덕션)에 대응할 수 있는 구조도 필요합니다:

my-react-project/
├── .env
├── .env.development
├── .env.staging
└── .env.production

각 파일에 환경별 설정을 정의하고, process.env.REACT_APP_* 형태로 접근할 수 있습니다.

7. 테스트

테스트 파일은 각 컴포넌트나 기능 근처에 위치시키는 것이 좋습니다:

src/
└── components/
    └── Button/
        ├── Button.js
        └── Button.test.js

통합 테스트나 E2E 테스트를 위한 별도의 디렉터리를 만들 수도 있습니다:

my-react-project/
└── tests/
    ├── integration/
    └── e2e/

8. 국제화 (i18n)

다국어 지원이 필요한 경우, 다음과 같은 구조를 사용할 수 있습니다:

src/
└── locales/
    ├── en/
    │   └── translation.json
    └── ko/
        └── translation.json

react-i18 next 라이브러리를 사용하여 국제화를 구현할 수 있습니다.


확장 가능한 React 프로젝트 구조를 설계하는 것은 프로젝트의 성공에 중요한 역할을 합니다. 이 블로그에서 제시한 구조는 하나의 가이드라인일 뿐이며, 실제 프로젝트의 요구사항에 따라 적절히 수정하여 사용해야 합니다.

 

주요 포인트를 정리하면 다음과 같습니다:

  1. 명확한 폴더 구조를 사용하여 코드를 논리적으로 구성합니다.
  2. 컴포넌트를 재사용 가능한 단위로 분리합니다.
  3. 상태 관리 전략을 신중히 선택합니다.
  4. API 통신을 위한 별도의 서비스 레이어를 만듭니다.
  5. 라우팅 구조를 명확히 정의합니다.
  6. 환경별 설정을 관리합니다.
  7. 테스트 코드를 체계적으로 구성합니다.
  8. 필요한 경우 국제화를 고려합니다.

이러한 구조를 바탕으로 프로젝트를 시작하면, 프로젝트가 성장함에 따라 발생할 수 있는 많은 문제들을 사전에 방지할 수 있습니다. 또한, 새로운 팀원이 프로젝트에 합류했을 때도 빠르게 코드베이스를 이해하고 작업을 시작할 수 있을 것입니다.

 

마지막으로, 프로젝트 구조는 고정된 것이 아니라 프로젝트의 요구사항과 팀의 선호도에 따라 계속해서 발전해 나가야 한다는 점을 기억하세요. 정기적인 리팩토링과 구조 개선을 통해 프로젝트를 건강하게 유지할 수 있습니다.

반응형