React Architecture : React 애플리케이션을 구조화하고 구성하는 방법
본문
새로운 React 애플리케이션을위한 아키텍처 설정에 대한 독자적인 가이드입니다.
React 애플리케이션을 구성하는 올바른 방법에 대한 합의가 없습니다. React는 당신에게 많은 자유를 제공하지만 그 자유와 함께 당신 자신의 아키텍처를 결정할 책임이 따릅니다.
종종 처음에 응용 프로그램을 설정하는 사람은 구성 요소 폴더에 거의 모든 것을 던지거나 Redux를 사용하는 경우 구성 요소와 컨테이너에 던지지 만 더 나은 방법이 있다고 제안합니다. 응용 프로그램을 사용, 이해 및 확장하기 쉽도록 구성하는 방법에 대해 신중하게 생각하고 싶습니다.
대규모 프로덕션 React 애플리케이션을위한 직관적이고 확장 가능한 시스템이라고 생각하는 것이 무엇인지 보여 드리겠습니다. 내가 중요하다고 생각하는 주요 개념은 유형이 아닌 기능에 중점을 둔 아키텍처를 만들고 글로벌 수준에서 공유 구성 요소 만 구성하고 다른 모든 관련 엔터티를 지역화 된 뷰에서 함께 모듈화하는 것입니다.
기술 가정
이 기사는 의견이 많으므로 프로젝트에서 사용할 기술에 대해 몇 가지 가정을 할 것입니다.
- Application - React (Hooks)
- Global state management - Redux, Redux Toolkit
- Routing - React Router
- Styles - Styled Components
- Testing - Jest, React Testing Library
스타일링 구성 요소, CSS 모듈 또는 사용자 지정 Sass 설정이 이상적이든 스타일에 대해 강한 의견을 갖고 있지는 않지만 스타일 구성 요소는 스타일을 모듈화 하는 데 가장 좋은 옵션 중 하나 일 것입니다.
또한 최상위 테스트 폴더가 아니라 테스트가 코드와 함께 있다고 가정합니다. 이 방법으로 어느 쪽이든 갈 수 있지만 예제가 작동하려면 실제 세계에서 결정을 내려야 합니다.
Redux Toolkit 대신 vanilla Redux를 사용하는 경우 여기에 있는 모든 것이 여전히 적용될 수 있습니다. Redux를 기능 슬라이스로 설정하는 것이 좋습니다.
Storybook에 대해서도 양가 적이지만 프로젝트에서 사용하기로 선택한 경우 해당 파일과 함께 표시되는 모습을 포함하겠습니다.
예를 들어 도서 목록 페이지, 저자 목록 페이지, 인증 시스템이 있는 "Library App"예제를 사용하겠습니다.
디렉토리 구조
최상위 디렉토리 구조는 다음과 같습니다.
- assets - 이미지, SVG, 회사 로고 등과 같은 글로벌 정적 자산
- components - 레이아웃 (래퍼, 탐색), 양식 구성 요소, 단추와 같은 전역 공유 / 재사용 가능 구성 요소
- services - 자바 스크립트 모듈
- store - 글로벌 Redux 스토어
- utils - 유틸리티, 도우미, 상수 등
- views - "페이지"라고도 할 수 있으며 대부분의 앱이 여기에 포함됩니다.
가능한 한 익숙한 규칙을 유지하는 것을 좋아하므로 src는 모든 것을 포함하고 index.js는 진입 점이며 App.js는 인증 및 라우팅을 설정합니다.
.
└── /src
├── /assets
├── /components
├── /services
├── /store
├── /utils
├── /views
├── index.js
└── App.js
TypeScript 프로젝트 인 경우 유형, 필요한 경우 미들웨어, 컨텍스트에 대한 컨텍스트 등과 같은 추가 폴더를 볼 수 있습니다.
Aliases
별칭을 사용하도록 시스템을 설정하여 구성 요소 폴더 내의 모든 항목을 @components, 자산을 @assets 등으로 가져올 수 있습니다. 사용자 지정 Webpack이 있는 경우 이는 확인 구성을 통해 수행됩니다.
module.exports = {
resolve: {
extensions: ['js', 'ts'],
alias: {
'@': path.resolve(__dirname, 'src'),
'@assets': path.resolve(__dirname, 'src/components'),
'@components': path.resolve(__dirname, 'src/components'),
// ...etc
},
},
}
프로젝트 내 어디에서나 가져 오기를 변경하지 않고 파일을 이동하는 것이 훨씬 쉬워지며 ../../../../../components/와 같은 것으로 끝나지 않습니다.
Components
구성 요소 폴더 내에서 양식, 표, 버튼, 레이아웃 등 유형별로 그룹화 합니다. 세부 사항은 특정 앱에 따라 다릅니다.
이 예제에서는 사용자가 고유 한 양식 시스템을 만들거나 기존 양식 시스템에 대한 고유 한 바인딩을 만드는 중이라고 가정합니다 (예 : Formik 및 Material UI 결합). 이 경우 각 구성 요소 (TextField, Select, Radio, Dropdown 등)에 대한 폴더를 만들고 내부에는 구성 요소 자체, 스타일, 테스트 및 사용 중인 경우 Storybook에 대한 파일이 있습니다.
- Component.js - 실제 React 컴포넌트
- Component.styles.js - 구성 요소의 스타일 구성 요소 파일
- Component.test.js - 테스트
- Component.stories.js - 스토리 북 파일
나에게 이것은 모든 구성 요소에 대한 파일을 포함하는 하나의 폴더, 모든 테스트를 포함하는 하나의 폴더, 모든 Storybook 파일을 포함하는 하나의 폴더 등을 갖는 것보다 훨씬 더 의미가 있습니다. 관련된 모든 것은 함께 그룹화 되고 찾기 쉽습니다.
.
└── /src
└── /components
├── /forms
│ ├── /TextField
│ │ ├── TextField.js
│ │ ├── TextField.styles.js
│ │ ├── TextField.test.js
│ │ └── TextField.stories.js
│ ├── /Select
│ │ ├── Select.js
│ │ ├── Select.styles.js
│ │ ├── Select.test.js
│ │ └── Select.stories.js
│ └── index.js
├── /routing
│ └── /PrivateRoute
│ ├── /PrivateRoute.js
│ └── /PrivateRoute.test.js
└── /layout
└── /navigation
└── /NavBar
├── NavBar.js
├── NavBar.styles.js
├── NavBar.test.js
└── NavBar.stories.js
components / forms 디렉토리에 index.js 파일이 있음을 알 수 있습니다. index.js 파일은 명시 적이 지 않기 때문에 사용을 피하는 것이 합당 하지만 이 경우에는 의미가 있습니다. 결국 모든 양식의 색인이 되고 다음과 같이 보입니다.
import { TextField } from './TextField/TextField'
import { Select } from './Select/Select'
import { Radio } from './Radio/Radio'
export { TextField, Select, Radio }
그런 다음 하나 이상의 구성 요소를 사용해야 할 때 한 번에 쉽게 가져올 수 있습니다.
import { TextField, Select, Radio } from '@components/forms'
이 방법은 양식 내의 모든 폴더 안에 index.js를 만드는 것보다 더 권장 할 것이므로 이제는 각 폴더에 대해 쉽게 가져올 수 있도록 10 개의 index.js 파일이 아니라 실제로 전체 디렉토리를 인덱싱 하는 하나의 index.js 만 있습니다. 개별 파일.
Services
서비스 디렉토리는 구성 요소보다 덜 중요하지만 나머지 애플리케이션에서 사용하는 일반 JavaScript 모듈을 만드는 경우 유용 할 수 있습니다. 일반적인 인위적인 예제는 다음과 같은 LocalStorage 모듈입니다.
.
└── /src
└── /services
├── /LocalStorage
│ ├── LocalStorage.service.js
│ └── LocalStorage.test.js
└── index.js
서비스의 예 :
export const LocalStorage = {
get(key) {},
set(key, value) {},
remove(key) {},
clear() {},
}
import { LocalStorage } from '@services'
LocalStorage.get('foo')
Store
전역 데이터 저장소는 저장소 디렉터리 (이 경우 Redux)에 포함됩니다. 각 기능에는 작업 및 테스트뿐만 아니라 Redux Toolkit 슬라이스가 포함 된 폴더가 있습니다. 이 설정은 일반 Redux에서도 사용할 수 있으며 슬라이스 대신 .reducers.js 파일과 .actions.js 파일을 생성하면 됩니다. sagas를 사용하는 경우 Redux Thunk 작업에 대해 .actions.js 대신 .saga.js가 될 수 있습니다.
.
└── /src
├── /store
│ ├── /authentication
│ │ ├── /authentication.slice.js
│ │ ├── /authentication.actions.js
│ │ └── /authentication.test.js
│ ├── /authors
│ │ ├── /authors.slice.js
│ │ ├── /authors.actions.js
│ │ └── /authors.test.js
│ └── /books
│ ├── /books.slice.js
│ ├── /books.actions.js
│ └── /books.test.js
├── rootReducer.js
└── index.js
모달, 토스트, 사이드 바 토글 및 기타 전역 UI 상태를 처리하기 위해 상점의 ui 섹션과 같은 것을 추가 할 수도 있습니다.이 상태는 전체적으로 const [isOpen, setIsOpen] = useState (false)를 사용하는 것보다 낫습니다.
rootReducer에서 모든 슬라이스를 가져와 combineReducer와 결합하고 index.js에서 저장소를 구성합니다.
Utils
프로젝트에 utils 폴더가 필요한지 여부는 사용자에게 달려 있지만 일반적으로 앱의 여러 섹션에서 쉽게 사용할 수 있는 유효성 검사 및 변환과 같은 일부 전역 유틸리티 기능이 있다고 생각합니다. 수천 개의 함수를 포함하는 하나의 helpers.js 파일 만 있는 것이 아니라 체계적으로 유지한다면 프로젝트 구성에 도움이 될 수 있습니다.
.
└── src
└── /utils
├── /constants
│ └── countries.constants.js
└── /helpers
├── validation.helpers.js
├── currency.helpers.js
└── array.helpers.js
다시 말하지만 utils 폴더에는 글로벌 수준에서 유지하는 것이 합리적이라고 생각하는 모든 것이 포함될 수 있습니다. "다중 계층"파일 이름을 선호하지 않는 경우 이름을 validation.js라고 부르면 됩니다.하지만 제가 보기에 명시 적이라고 해서 프로젝트에서 어떤 것도 빼앗아 가지 않으며 검색 할 때 파일 이름을 쉽게 탐색 할 수 있습니다. IDE에서.
Views
앱의 주요 부분은 다음과 같습니다 : views 디렉토리. 앱의 모든 페이지는 "보기"입니다. 이 작은 예에서 뷰는 Redux 스토어와 꽤 잘 어울리지 만 스토어와 뷰가 정확히 동일한 경우는 아니므로 서로 분리되어 있습니다. 또한 책은 저자 등으로부터 가져올 수 있습니다.
뷰 내의 모든 항목은 해당 특정 뷰 내에서만 사용될 가능성이 높은 항목입니다. / books 경로에서만 사용되는 BookForm과 / authors 경로에서만 사용되는 AuthorBlurb입니다. 특정 양식, 모달, 버튼, 전역이 아닌 모든 구성 요소가 포함될 수 있습니다.
모든 페이지를 구성 요소 / 페이지에 모으는 대신 모든 페이지를 도메인 중심으로 유지하는 이점은 응용 프로그램의 구조를 보고 얼마나 많은 최상위 뷰가 있는지 알 수 있으며 모든 것이 어디에 있는지 알 수 있다는 것입니다. 그보기에 의해 사용됩니다. 내포 된 경로가 있는 경우 언제든지 기본 경로 내에 내포 된 뷰 폴더를 추가 할 수 있습니다.
.
└── /src
└── /views
├── /authors
│ ├── /AuthorsPage
│ │ ├── AuthorsPage.js
│ │ └── AuthorsPage.test.js
│ └── /AuthorBlurb
│ ├── /AuthorBlurb.js
│ └── /AuthorBlurb.test.js
├── /books
│ ├── /BooksPage
│ │ ├── BooksPage.js
│ │ └── BooksPage.test.js
│ └── /BookForm
│ ├── /BookForm.js
│ └── /BookForm.test.js
└── /login
├── LoginPage
│ ├── LoginPage.styles.js
│ ├── LoginPage.js
│ └── LoginPage.test.js
└── LoginForm
├── LoginForm.js
└── LoginForm.test.js
그런 식으로 프로젝트를 설정 한 적이 없다면 폴더 안에 모든 것을 보관하는 것이 성가신 것처럼 보일 수 있습니다. 항상 더 평평하게 유지하거나 나머지 앱을 모방 한 자체 디렉터리로 테스트를 이동할 수 있습니다.
결론
이것은 대규모 프로덕션 앱에 맞게 확장되고 테스트 및 스타일링을 처리하고 기능 중심의 방식으로 모든 것을 함께 유지하는 React 조직을 위한 시스템에 대한 저의 제안입니다. 구성 요소와 컨테이너에 있는 모든 것의 기존 구조보다 더 중첩되어 있지만 Redux가 Hooks로 구현하기 훨씬 쉽고 "스마트"컨테이너와 "멍청한"구성 요소가 더 이상 필요하지 않기 때문에 해당 시스템은 좀 더 오래되었습니다.
이 시스템을 보고 앱에 필요한 모든 것을 이해하고 특정 섹션에서 작업 할 위치 또는 앱에 전 세계적으로 영향을 미치는 구성 요소를 이해하는 것은 쉽습니다. 이 시스템은 모든 유형의 앱에 적합하지 않을 수 있지만 저에게는 효과적이었습니다. 이 시스템을 개선 할 수 있는 방법이나 장점이 있는 다른 시스템에 대한 의견을 듣고 싶습니다.
https://www.taniarascia.com/react-architecture-directory-structure/
- 이전글React 개발자 로드맵 21.07.12
- 다음글복잡한 반응 경험을 위한 키보드 접근성을 디자인하는 방법 21.06.21