Khi mới học React, hầu hết mọi người đều bắt đầu với một dự án đơn giản: một thư mục src/ chứa vài file .jsx nằm lộn xộn cạnh nhau. Ban đầu điều này không sao cả - nhưng chỉ cần dự án phát triển thêm vài chục component, bạn sẽ thấy việc tìm một file trở nên cực kỳ mất thời gian. Bài viết này sẽ giúp bạn hiểu cách tổ chức thư mục React một cách hợp lý, từ dự án nhỏ đến dự án lớn, để code luôn dễ đọc, dễ bảo trì và dễ mở rộng.
Tại sao cấu trúc thư mục lại quan trọng?
Một cấu trúc thư mục tốt không làm ứng dụng chạy nhanh hơn, nhưng nó mang lại những lợi ích rất thực tế:
- Dễ đọc hơn: nhìn vào thư mục là biết ngay từng phần code nằm ở đâu.
- Dễ mở rộng: khi thêm tính năng mới, bạn biết chính xác nên đặt file ở đâu.
- Dễ làm việc nhóm: người mới vào dự án có thể định hướng nhanh chóng.
- Tính module hóa cao: khuyến khích tách component thành các phần tái sử dụng được.
Bản thân React không quy định bạn phải tổ chức thư mục theo cách nào - thư viện này không có ý kiến gì về vấn đề đó. Điều quan trọng là bạn chọn một cách tiếp cận phù hợp với quy mô dự án và áp dụng nó một cách nhất quán.
Giai đoạn 1: Khi dự án còn rất nhỏ
Khi bạn mới create-react-app hoặc dựng project bằng Vite, thư mục src/ gần như trống trơn, chỉ có file App.jsx là điểm khởi đầu. Với dự án nhỏ (dưới 10-15 component), nhiều người chỉ cần hai thư mục đơn giản:
src/
├── components/
├── hooks/
├── App.jsx
└── main.jsx
Ở giai đoạn này việc gom mọi thứ vào một chỗ không gây vấn đề gì lớn. Nhưng nếu bạn cứ để mọi file rời rạc ngay trong src/ - kiểu như Navbar.jsx, Footer.jsx, Home.jsx, Login.jsx, Button.jsx... nằm cạnh nhau - thì chỉ sau khoảng 30 file, việc tìm kiếm sẽ bắt đầu trở nên khó chịu. Đó chính là lúc bạn cần một cấu trúc rõ ràng hơn.
Giai đoạn 2: Cấu trúc trung cấp - nhóm theo loại file
Đây là cấu trúc phổ biến nhất cho người mới, và cũng được nhắc đến trong tài liệu chính thức của React như một cách tiếp cận đơn giản: nhóm các file theo loại (component vào thư mục components, hook vào thư mục hooks, context vào thư mục context...).
src/
├── assets/
├── components/
├── pages/
├── layouts/
├── hooks/
├── context/
├── services/
├── utils/
├── constants/
├── routes/
├── styles/
├── App.jsx
└── main.jsx
Mỗi thư mục đảm nhận một trách nhiệm rõ ràng:
- assets/ - chứa hình ảnh, font chữ, icon và các file tĩnh khác. Gom mọi tài nguyên vào một nơi giúp việc quản lý dễ dàng hơn nhiều.
- components/ - nơi chứa các UI component có thể tái sử dụng ở nhiều nơi khác nhau (nút bấm, thẻ hiển thị, ô nhập liệu...). Nếu một component chỉ dùng ở đúng một chỗ, đôi khi nên cân nhắc đặt nó gần nơi sử dụng thay vì bỏ chung vào đây.
- pages/ - mỗi file đại diện cho một màn hình hoàn chỉnh, được ghép lại từ nhiều component nhỏ trong
components/. - layouts/ - chứa các khung bố cục dùng chung (header, sidebar, footer...) để tránh lặp code giữa các trang.
- hooks/ - nơi lưu các custom hook. Khi mới học React, nhiều người chỉ dùng hook có sẵn như
useState,useEffect; nhưng khi logic phức tạp hơn, việc tách ra custom hook và gom vào một thư mục riêng sẽ giúp code sạch hơn rất nhiều. - context/ - nếu bạn dùng React Context API để quản lý state toàn cục, hãy giữ mọi context ở đây cho gọn gàng.
- services/ - xử lý các lời gọi API. Thay vì gọi API rải rác khắp nơi trong component, hãy tạo các file service riêng để tách biệt phần logic nghiệp vụ khỏi phần giao diện.
- utils/ - chứa các hàm tiện ích nhỏ, dùng đi dùng lại nhiều lần (định dạng ngày tháng, xử lý chuỗi...).
- constants/ - lưu các giá trị ít thay đổi, tránh việc phải gõ lại giá trị "hard-code" nhiều lần trong code.
- routes/ - khi ứng dụng có nhiều trang, việc tách cấu hình định tuyến ra khỏi
App.jsxgiúp file gốc gọn gàng và dễ quản lý hơn. - styles/ - chứa file CSS toàn cục. Nếu bạn dùng Tailwind CSS, thư mục này thường sẽ rất nhỏ vì phần lớn style đã nằm ngay trong class của component.
Cấu trúc này phù hợp với phần lớn dự án React ở mức beginner và intermediate. Nó bao phủ gần như mọi loại file thường gặp, nên trong thư mục gốc src/ gần như chỉ còn lại App.jsx và main.jsx.
Ví dụ cách tổ chức bên trong components/
Một cách phổ biến khác - cũng được đề cập trong tài liệu chính thức của React trước đây - là gom các file liên quan đến cùng một component (JS, CSS, test) vào chung một thư mục con:
components/
├── Button/
│ ├── Button.jsx
│ ├── Button.module.css
│ └── Button.test.jsx
├── Card/
│ ├── Card.jsx
│ └── Card.module.css
└── Input/
├── Input.jsx
└── Input.test.jsx
Cách này giúp mọi thứ liên quan đến một component nằm gọn trong một chỗ - sửa component nào, bạn chỉ cần mở đúng một thư mục.
Giai đoạn 3: Cấu trúc nâng cao - nhóm theo tính năng (feature-based)
Khi dự án lớn dần, một vấn đề sẽ xuất hiện: rất nhiều component, hook hay logic không còn thuộc riêng về một "trang" nào nữa mà được dùng chung ở nhiều nơi. Lúc này, cách tổ chức theo loại file (components, hooks, pages...) bắt đầu bộc lộ hạn chế - mỗi khi sửa một tính năng, bạn phải nhảy qua lại giữa nhiều thư mục khác nhau.
Giải pháp là chuyển sang feature-based structure: gom mọi thứ liên quan đến một tính năng nghiệp vụ (feature) vào chung một thư mục, thay vì tách theo loại kỹ thuật.
src/
├── features/
│ ├── auth/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── services/
│ │ └── index.js
│ ├── todos/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── services/
│ │ └── index.js
│ └── customer/
│ ├── components/
│ │ ├── customer-form/
│ │ └── customer-detail/
│ └── utils/
│ └── address/
├── components/ # UI component dùng chung toàn app (Button, Input, Modal...)
├── hooks/ # hook dùng chung toàn app
├── context/
├── services/ # cấu hình API dùng chung
├── utils/
└── App.jsx
Ưu điểm lớn nhất của cách tổ chức này là mỗi tính năng gần như độc lập với nhau, giảm thiểu xung đột khi nhiều người cùng làm việc trên một dự án. Nhóm A có thể chỉnh sửa features/auth/ mà không ảnh hưởng tới nhóm B đang làm features/todos/. Còn thư mục components/ ở cấp cao nhất chỉ nên chứa những UI component thực sự dùng chung (button, input, dropdown, modal...), phân biệt rõ với các component đặc thù riêng cho một tính năng.
Việc chia nhỏ đến đâu, có nên thêm thư mục utils/ con trong từng feature hay không, hoàn toàn tùy vào sở thích cá nhân hoặc quy ước của nhóm bạn - không có một công thức "đúng tuyệt đối" nào cho việc này.
Một vài nguyên tắc đặt tên và tổ chức nên nhớ
- Nhất quán là quan trọng nhất. Dù bạn chọn PascalCase (
MyComponent.jsx) hay có dùngindex.jscho từng thư mục component hay không, hãy giữ nguyên cách đó xuyên suốt dự án. index.jstrong mỗi thư mục component giúp import gọn hơn (không cần lặp lại tên component), nhưng đổi lại khi tìm kiếm file bằng tên, bạn sẽ thấy rất nhiều fileindex.jstrùng tên, hơi khó phân biệt. Đây là sự đánh đổi, không có lựa chọn nào tuyệt đối tốt hơn.- Nếu một component chỉ được import bởi đúng một component khác, hãy cân nhắc đặt nó ngay trong cùng file hoặc cùng thư mục với "cha" của nó, thay vì tách ra một thư mục riêng biệt không cần thiết.
- Đừng để component quá dài. Một sai lầm phổ biến của người mới là viết một component hơn 500 dòng code. Khi thấy file quá dài, hãy tách nhỏ thành các component con - vừa dễ đọc, vừa dễ debug hơn.
- Không cần theo đúng 100% một cấu trúc mẫu nào. Hãy xem các cấu trúc ở trên là gợi ý, không phải quy tắc cứng. Bạn hoàn toàn có thể điều chỉnh sao cho phù hợp với đặc thù dự án của mình.
Nên chọn cấu trúc nào?
Không có một cấu trúc "chuẩn" duy nhất cho mọi dự án React - đây thực sự là chủ đề gây tranh cãi nhiều trong cộng đồng, vì nó phụ thuộc rất nhiều vào quy mô và đặc thù từng dự án. Tuy vậy, bạn có thể tham khảo quy tắc chọn nhanh sau:
| Quy mô dự án | Cấu trúc gợi ý |
|---|---|
| Rất nhỏ (dưới 10-15 component) | components/ + hooks/ đơn giản |
| Nhỏ đến trung bình | Nhóm theo loại file (components, pages, hooks, services...) |
| Lớn, nhiều tính năng, nhiều người làm cùng | Nhóm theo tính năng (features/) kết hợp thư mục dùng chung |
Nếu bạn dùng framework có sẵn quy ước như Next.js, phần định tuyến theo trang sẽ được framework quyết định sẵn, giúp việc chọn cấu trúc dễ hơn nhiều. Còn nếu dùng Vite hoặc Create React App thuần, bạn sẽ cần tự thiết kế cấu trúc - và đó chính xác là lúc những nguyên tắc ở trên phát huy tác dụng.
Tổng kết
Cấu trúc thư mục React không có công thức duy nhất đúng cho tất cả mọi người - quan trọng là nó phải phù hợp với quy mô dự án hiện tại và có khả năng phát triển cùng dự án trong tương lai. Với người mới bắt đầu, lời khuyên đơn giản nhất là:
- Bắt đầu tối giản - đừng over-engineer ngay từ đầu.
- Khi số lượng file tăng lên và bắt đầu khó tìm, chuyển sang nhóm theo loại file (
components,pages,hooks,services...). - Khi dự án đủ lớn và nhiều phần logic dùng chung nhiều nơi, cân nhắc chuyển sang tổ chức theo tính năng (
features/). - Dù chọn cách nào, hãy giữ sự nhất quán trong toàn bộ dự án - đó mới là yếu tố quyết định giúp code dễ đọc và dễ bảo trì về lâu dài.
Một cấu trúc thư mục gọn gàng không khiến bạn viết code "thông minh" hơn, nhưng nó chắc chắn khiến hành trình phát triển dự án của bạn - và của cả những người sẽ đọc code này sau bạn - nhẹ nhàng hơn rất nhiều.







