Nếu bạn từng phải nhảy vào một codebase React cũ kỹ và cảm giác như mình đang thám hiểm trong một mê cung hỗn độn — bạn không hề cô đơn. Qua nhiều năm làm việc trên đủ thứ từ MVP sơ khai đến các ứng dụng chạy thực tế ở quy mô lớn, tôi nhận ra một điều rất rõ ràng: cấu trúc dự án cực kỳ quan trọng.
Trong bài viết này, tôi sẽ chia sẻ cách tôi tổ chức các dự án React của mình, lý do tôi chọn định dạng này và cách nó mở rộng một cách gọn gàng theo thời gian.
Triết lý cốt lõi
Trước khi đi sâu vào cây thư mục, đây là những nguyên tắc dẫn dắt quyết định của tôi:
- Tách biệt trách nhiệm hơn là trừu tượng hóa chỉ để cho có.
- Suy nghĩ theo tính năng — file phải nằm ở nơi nó thuộc về một cách logic.
- Khả năng mở rộng — cách tổ chức cho 3 component vẫn phải hoạt động tốt với 300 component.
- Trải nghiệm lập trình viên — dễ tiếp cận, ít phải chuyển ngữ cảnh.
Cấu trúc thư mục
Đây là bố cục cấp cao mà tôi gần như luôn áp dụng trong mọi dự án React:
src/
│
├── assets/ # Images, fonts, global styles, etc.
├── components/ # Reusable UI components (atoms/molecules)
├── features/ # Feature-based modules (e.g. auth, dashboard)
├── hooks/ # Custom React hooks
├── lib/ # Utilities and shared logic (API clients, helpers)
├── pages/ # Route-based components (if using file-based routing)
├── layouts/ # Layout wrappers (MainLayout, AuthLayout, etc.)
├── store/ # Global state (Redux, Zustand, etc.)
├── types/ # TypeScript types and interfaces
└── App.tsx # Root component
Phân tích chi tiết
1. components/
- Nơi bạn xây dựng “design system”.
- Button.tsx, Modal.tsx, Input.tsx v.v.
- Những UI block nhỏ, thuần túy, dễ tái sử dụng.
- Nếu nó có thể xuất hiện ở nhiều trang, rất có thể nên để ở đây.
2. features/
Đây là trái tim của ứng dụng, được tổ chức theo từng domain/tính năng.
features/
├── auth/
│ ├── LoginForm.tsx
│ ├── authSlice.ts
│ ├── api.ts
│ └── hooks.ts
└── dashboard/ ├── DashboardPage.tsx ├── widgets/ └── dashboardSlice.ts
Mọi thứ mà một tính năng cần (component, hook, state cục bộ) đều được đóng gói bên trong. Cách này giúp module dễ kiểm thử, dễ bảo trì.
3. hooks/
- Các custom hook như
useDebounce
,useFetch
,useOnClickOutside
. - Thường được dùng xuyên suốt features và components.
- Mỗi hook nên có một nhiệm vụ đơn nhất.
4. lib/
“Thắt lưng công cụ” cho app, ví dụ:
- Axios instance
- Hàm format ngày/giờ
- Hàm validation
- Mọi thứ không gắn trực tiếp vào UI
5. store/
Dành cho quản lý state toàn cục (khi cần):
- Thiết lập store Redux hoặc Zustand
- Middleware, logic persistence
- Các slice riêng theo tính năng nên đặt trong thư mục
features/
liên quan
6. types/
- Nơi tập trung các loại type và interface dùng chung.
- Nếu bạn dùng TypeScript (bạn nên dùng!), điều này giúp tránh việc type lan tràn khắp dự án như cỏ dại.
Các công cụ & quy ước tôi sử dụng
- Path alias qua
tsconfig.json
(@components
,@features
, v.v.) - Tư duy Atomic Design, áp dụng linh hoạt
- Prettier + ESLint + Husky để giữ code sạch, thống nhất
- Storybook để phát triển và tài liệu hóa component
Vì sao cách làm này hiệu quả?
- Dễ tiếp cận: Lập trình viên mới có thể nhanh chóng tìm thấy thứ họ cần.
- Mở rộng mượt mà: Khi app lớn dần, cấu trúc này không bị sụp đổ.
- Linh hoạt: Hỗ trợ SSR (Next.js), SPA hoặc Electron chỉ với điều chỉnh nhỏ.
- Dễ kiểm thử: Mỗi feature độc lập, viết test đơn vị hay tích hợp đều đơn giản.
Lời kết
Không có một “cách đúng duy nhất” để tổ chức dự án React — nhưng chắc chắn có những cách tốt hơn. Mấu chốt là luôn nhất quán, suy nghĩ dựa trên tính năng và khả năng tái sử dụng, đồng thời cân nhắc việc dự án sẽ phát triển ra sao.
Dù bạn đang xây dựng một dự án phụ hay một ứng dụng quy mô startup, một cấu trúc vững chắc chính là nền tảng của code sạch và dễ bảo trì.
Bạn tổ chức dự án React của mình như thế nào? Hãy chia sẻ mẹo hoặc câu chuyện thực chiến của bạn trong phần bình luận!