😎나만의 리액트 설계 방법
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
├── index.tsx
├── App.tsx
├── components
│ ├── atomic //가장 작은 단위 ex) 버튼, text, 수평선...
│ │ └── Button
│ │ ├── index.tsx //컴포넌트 함수
│ │ ├── styled.(ts | css) //스타일
│ │ └── types.ts //타입스크립트 적용 시 props에 대한 정의필요하므로 타입선언
│ ├── molecules //2개 이상의 atomic ex) 인풋+버튼 => 입력창
│ ├── organisms // atomic과 molecules가 합쳐진 곳 중복되지 않음
│ ├── templates // 하위 항목의 컴포넌트들을 배치하고 설계한 구조
│ └── pages // templates 하나만 받아와 로직을 작동
├── store //전역상태 관리
├── hooks //커스텀 Hook 폴더
├── styles //기본 스타일 전역 선언 및 theme사용
├── routes // 리액트 라우터 함수
├── constants // 상수
├── apis //API모음
└── utils //재사용 함수모음, reducer 포함
설계를 고민하는 이유
프로젝트를 시작하기 전 항상 디렉터리 구조에 대해 많은 고민을 한다. 디렉터리를 고민하는 것은 프로젝트를 어떻게 설계할 것이냐 라고 생각한다. 왜냐하면 구현해야 하는 작업을 순서대로 하게 된다면 작은 단위에서 큰 단위로 만들게 되기 때문에 디렉터리 구조가 프로젝트 작업프로세스에 영향을 미친다고 생각한다. 컴포넌트를 폴더에 컴포넌트 함수파일과 스타일파일을 따로 분리할지, import export 방식은 어떻게 할지를 생각한다. 이 고민을 하는 이유가 뭘까 곰곰이 생각해보니 얼마나 효율적인 개발방법 모색이다.
컴포넌트 vs 비컴포넌트
나는 리액트 개발 시 로직과 컴포넌트를 분리하려고 최대한 노력한다. 이 방법의 장점은 로직이 한눈에 보여진다는 점이 있고 단점은 컴포넌트 구현 시 많은 props들이 생겨날 수 있다는 점이다.
위의 디렉터리 구조는 많은 고민을 하고 지금까지 해왔던 프로젝트에서 가장 괜찮다고 생각한 부분과 atomic design을 합성해 설계한 구조이다. 구조는 컴포넌트 모음과 비 컴포넌트 모음으로 분리되어있다. 이렇게 한 이유는 컴포넌트에는 컴포넌트만 들어가게 해야 로직의흐름을 이해하기 편하다고 생각한다. 그러면 무조건 분리되어 있냐는 아니다. pages에서 데이터를 불러와 props로 내려주거나, 전역상태에서 컴포넌트에 넣어주면 되기 때문에 이는 프로젝트 특성상 조금은 달라질 수 있다.
규칙
컴포넌트 선언
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//index.(jsx | ts)
// 1. import 라이브러리, 연관된 것, 멀리있는것부터 순서대로
// 2. 컴포넌트 정의 (함수선언식으로 정의)
// 3. propType TS 쓸 때는 types.ts로 선언
// 4. 간단한 상수 설정(컴포넌트 함수 외부)
// 5. 해당 컴포넌트에서만 사용할 함수
//styled.(js | ts)
//export const 컴포넌트 명
//export const 컴포넌트 명
//export const 컴포넌트 명
//index에서 불러올 때는 import * as S from "./styled"
// 사용시 <S.컴포넌트 />
//types.ts
// Props정의
store
- 전역 상태를 정할 때는 propDrilling을 피하기 위해 확인 후 사용한다.
- propDrilling을 해결하기 위해 합성 컴포넌트를 사용할 수 있지만 결합도를 따져 전역상태를 사용할지 정한다.
hooks
- 컴포넌트에서 hook을 따로 정의한다.
- 공통된 로직이 있는 경우 커스텀 훅으로 만든다.
constants
- 2번이상 공통되는 매직스트링, 매직넘버를 피하기 위해
관련이름명.(js|ts)
로 한다.
apis
- 백엔드와 통신을 유의하여 파라미터로 url주소나 토큰을 받는 request라는 재사용 함수를 선언한다.
- 이후
관련페이지이름.(js|ts)
로 짓고 해당 url, options를 받는 함수들을 request에서 불러와 조합하여 사용한다.
utils
- 최대한 재사용가능한 순수 함수들을 모아 놓는다.
방향성을 가지자
리액트에서는 구조를 따로 정의하지 않았기 때문에 설계는 다양하다고 생각한다. 또한 나도 작은 프로젝트는 많이 해봤지만 상대적으로 규모가 큰 프로젝트 경험은 많지 않기에 내가 설계한 구조를 절대적 맹신은 하지는 않는다.
다만 새롭게 시작 또는 팀에 합류해서 프로젝트 시작 시 어느정도 가이드 라인이 있으면 내가 정한 설계에서 변화에 대처하는 기준선이 될 것이라 생각한다.