들어가며
나는 작년부터 지금까지 리액트를 이용해서 여러 프로젝트들을 했다. 리액트를 배운 지 얼마 안 됐을 때는 책에서 배운 대로, 인강에서 배운 대로만 따라 하느라 큰 고민을 하지 않았었다. 그러나 어느 정도 경험이 생기고, 여러 팀 프로젝트를 참여하면서 팀원들과 의견을 나누다 보니, 프로젝트를 시작할 때 어떤 리액트 패턴을 사용할지, 폴더구조는 어떻게 가져갈지에 대한 고민을 하게 되었다.
이런 고민을 하는 과정에서 배운 내용들을 토대로 포스팅을 작성해보려고 한다.
❓ 리액트 컴포넌트 패턴은 뭐가 있고 어떤걸 사용할까
리액트는 정말 자유로운 라이브러리 이기 때문에, 다양한 패턴들이 존재한다. 그중에서 어떤 방식을 사용할지는 개발자가 정하는 것이기 때문에, 우리는 새로운 프로젝트를 시작할 때 이런 고민을 안 할 수가 없다. 정답이 없기 때문에 항상 프로젝트에 맞는 패턴을 고르는 게 좋은데, 대표적으로 리액트의 패턴들은 어떤 게 있는지 알아보자.
1. Presentation Component - Container Component
React의 가장 기본적이고 유명한 디자인 패턴이다. Container Component에서 데이터를 처리하고 Presentation Component에서 데이터를 출력하는 형태이다. 이렇게 나누는 이유는 하나의 컴포넌트에서 api 호출, 이벤트 함수, 비즈니스 로직, 상태관리, 예외처리들이 모두 담겨있으면 파일 하나하나가 엄청 커지게 되고, 특히 회사에서는 유지보수가 굉장히 힘들어진다. 그래서 UI와 로직을 서로 분리해서 관리하기 위한 패턴이다. 아래의 간단한 예시를 보자.
하나의 컴포넌트에서 로직과 UI를 담당하는 형태의 코드는 아래와 같다.
위에 코드를 presentation, container component로 분리하면 아래와 같다.
로직과 UI를 분리해서 로직을 props로 넘겨주는 식이다. 당장은 엄청 간단한 기능 이기때문에 크게 차이가 없어 보일 수 있지만 로직과 UI가 복잡해지면, 코드가 매우 길어지고 보기도 힘들어진다. 개발자들이 자주 이용하는 velog 서비스도 이런 presentation, container 패턴을 이용하고 있다. (velog Github)
Rudux의 창시자이며, 현재는 Meta(Facebook) React Core팀의 일원인 Dan Abramov가 작성한 presentaion, container 패턴에 대한 포스팅이 있는데, 포스팅 상단을 보면 현재는 이런 패턴을 이용하지 않는다고 한다. 사용하지 않는 이유는 아래에 있는 Component - Hooks 패턴으로 이 모든 작업이 대체가 가능하고, 더불어 hooks 패턴은 UI 뿐만 아니라 로직까지 재활용이 가능해진 다는 점 때문이다.
2. Component - custom hooks
custom hooks 패턴은 기존 presentation, container 패턴에서 로직을 hooks로 관리하는걸 말한다. 기존 container에서는 공통 로직이 발생했을 때 다른 container 컴포넌트로 로직을 넘겨주지 못했는데, hooks로 로직을 관리하게 되면, UI 재사용을 넘어서 로직까지 재사용이 가능해진다. 위에서 작성한 Login 로직을 hooks로 분리하면 아래와 같다.
해당 로직이 필요한 컴포넌트에서 hooks를 불러오기만 하면 로직을 사용할 수 있다. custom hooks에 관련된 진유림 님의 강의도 참고해보자
3. atomic 구조
atomic 구조는 리액트 컴포넌트를 Atom(원자) 단위로 설계하는 구조를 말한다. 간단하게 말해서 원자가 결합하여 분자가 되고, 분자가 결합하여 유기체가 되는 거처럼 컴포넌트를 가장 작은 단위에서 하나씩 결합하여 만드는 형태이다.
Atoms
HTML 태그 같은 label, input, button, link, 태그들처럼 가장 작은 단위의 컴포넌트를 말한다.
Molecule
Atom을 여러개 조합한 컴포넌트이다.
Oraganisms
Molecule과 Atom들을 조합하여 만든 컴포넌트이다.
Templates
위에서 만든 컴포넌트들을 넣을 레이아웃 컴포넌트이다
Pages
Templates에 위에서 만든 컴포넌트들을 다 주입한 컴포넌트이다.
Atomic 구조는 UI 재사용성이 매우 뛰어나서 협업 프로젝트에서 빠른 개발을 할 수 있는 패턴이다. 하지만 디자인 시스템을 구축하기 위한 초기 비용이 많이 들고, 로직과 State 들을 낮은 단위의 컴포넌트에서 다루지 못하고 page 단위에서 props로 내려줘야 하는 단점이 있다. props를 깊게 깊게 넣어줘야 하기 때문에 의도지 않은 props를 내려주는 실수가 있을 수도 있다.
초기 프로젝트 폴더 구조를 설계할 때 이 패턴들 중에 어떤 게 나의 프로젝트와 어울릴지를 잘 판단해서 골라야 한다. 디자인이 잘 나와있어서 디자인 시스템을 구축하기 편한 환경이라면 atomic 구조를 잘 활용할 수 있겠지만, 기획과 디자인이 자주 변경되는 환경에서는 atomic 디자인을 추천하지 않는다.
❓ 폴더 구조는 어떻게 가져가는 게 좋을까
폴더구조도 검색하면 정말 다양한 폴더구조들이 나온다. 여러 프로젝트들과, 검색 결과를 통해 많이 나왔던 폴더들을 나열하면 다음과 같다.
- pages -> 각 페이지들
- components -> 컴포넌트 들
- hooks -> hooks들
- styles -> style 코드
- types (ts + react 조합일 경우) -> type들
- assets (or static) + images, icons -> 이미지 or 아이콘 같은 정적 파일들
- utils -> 프로젝트에 이용되는 유틸 함수들
- api -> api 목록들
- lib -> 잡다 한 거? (너무 범위가 넓어서 애매하다)
- stores (or redux or recoil.... ) -> 전역 상태 폴더
내가 그동안 진행했던 프로젝트에서는 components 폴더 내부에 각 도메인 별로 (auth, post, tutorial, mypage) 폴더를 만든 뒤에 해당 도메인에서 사용되는 component들을 넣어놓고, 공통으로 사용되는 component들은 components/common 폴더에 넣어놓고 사용했었다.
이렇게 설계했을 때의 장점은 도메인 별로 컴포넌트를 나눠놔서 코드를 수정해야 하거나, 추가해야 할 때 쉽게 컴포넌트를 찾을 수 있어서 좋았다.
이렇게 컴포넌트들을 도메인별로 나누고 각 폴더 내부에는 해당 도메인에서 사용되는 hooks들과 컴포넌트를 테스트하는 test 폴더를 만들어서 해당 도메인의 로직 관리, 테스트 관리 코드를 넣어놨다.
hooks를 처음에는 src/hooks폴더에 다 넣고 관리했었는데, 생각해보면 어차피 각 도메인 내부에서만 사용되는 로직이라 재활용도 안되기 때문에 굳이 공용 hooks 쪽에 놔둘 필요가 없다고 판단해서 해당 컴포넌트 내부로 옮겼다.
만약 2번 이상 사용되는 hooks라면 공용 hooks 쪽에 넣어놓는 식으로 해서 재사용 hooks들은 한 공간에 넣는 식으로 규칙을 정했다.
마치며
새로운 프로젝트를 할 때 팀원과 같이 개발환경을 세팅하고, 폴더 구조, 라이브러리를 정하는 과정이 매우 어려운 거 같다. 각자 개발해온 과정도 많이 다르고, 추구하는 스타일도 많이 다른데 그걸 하나로 맞춰서 개발한다는 거 자체가 쉽지 않은 일이다. 그래도 이렇게 팀원과 같이 얘기하다보면 배우는 점도 많고 내가 몰랐던 사실들도 많이 알아가기 때문에 소통을 계속 하면서 서로 맞춰나가면 좋을 거 같다. 다들 화이팅!
'React' 카테고리의 다른 글
React Testing Library(RTL) 사용법 (0) | 2022.03.28 |
---|---|
[컴포넌트 재활용하기] - Button (2) | 2022.02.19 |
Recoil에서 Redux로 마이그레이션 하게 된 이유 (1) | 2022.01.16 |
리액트 라이프 사이클 - useEffect (0) | 2022.01.08 |
React Router v6 업데이트 정리 (0) | 2021.12.29 |
댓글