Dưới đây là bảng phân biệt chi tiết giữa Shared Component và Feature Component – một khái niệm cốt lõi trong kiến trúc Feature-Based (hay Feature-Sliced) thường được dùng trong các dự án React/Next.js quy mô lớn (như hệ thống ERP).
1. Bản chất & Phạm vi (Scope)
| Tiêu chí | Shared Component (Dùng chung) | Feature Component (Đặc thù tính năng) |
|---|---|---|
| Bản chất | Là các "viên gạch" cơ sở, thành phần UI nguyên thủy hoặc các widget thuần túy. | Là các "khối nhà" được xây dựng bằng cách ghép các viên gạch (Shared Component) lại với nhau. |
| Sự tái sử dụng | Rất cao. Được dùng ở bất kỳ đâu trên toàn bộ ứng dụng. | Rất thấp. Chỉ được dùng trong khuôn khổ của một tính năng cụ thể. |
| Logic nghiệp vụ (Business Logic) | Agnostic (Mù tịt): Nó không cần biết dữ liệu nó đang hiển thị là của ai hay ở đâu ra. Nó chỉ quan tâm đến Props được truyền vào (VD: text là gì, onSelect thì làm gì). | Tightly Coupled (Gắn chặt): Nó biết rõ nó đang xử lý dữ liệu gì (VD: Đang sửa loại vải nào, cần lấy schema nào để validate). |
| Khả năng import chéo | Feature Components được phép import Shared Components. | CẤM KỴ: Shared Component không bao giờ được import một Feature Component. Không nên có import chéo giữa 2 Feature khác nhau (trừ khi thông qua một Feature chuyên làm Shared/Domain). |
2. Vị trí thư mục điển hình
- Shared Component: Thường nằm ở
src/shared/components/hoặcsrc/components/. - Feature Component: Thường nằm ở
src/features/[tên-tính-năng]/components/.
3. Ví dụ thực tế từ dự án Vĩnh Phát ERP
VÍ DỤ 1: Shared Component
Các file như Button, Combobox, TagInput, AdvancedImageUploader
- Đặc điểm: Thằng
Comboboxchỉ biết là nhận vào một danh sách options (value, label) và bắn ra sự kiện onChange(value). - Nó không quan tâm danh sách đó là "Danh sách Nhóm vải", "Danh sách Khách hàng" hay "Danh sách Nhân viên". Bạn có thể dùng
Comboboxở form tính lương, cũng có thể dùng ở form nhập kho.
VÍ DỤ 2: Feature Component
Các file như FabricInfoTab.tsx, FabricCatalogForm.tsx (thuộc tính năng fabric-catalog)
- Đặc điểm: Thằng
FabricInfoTabbiết rất rõ nó đang gọi API nào (thông qua uploadImageMutation), nó gọi hook useContext và biết chắc chắn form này đang dùng cấu trúc dữ liệu FabricCatalogFormValues. - Nó render cứng các label như "Tên loại vải", "Thành phần". Bạn không thể đem
FabricInfoTabqua trang "Tạo Đơn Hàng" để xài được.
4. Dấu hiệu nhận biết nhanh khi đọc code
- Nhìn vào Imports:
- Nếu component import trực tiếp API Services, Database Types đặc thù của 1 bảng, State Management (Zustand store của tính năng đó) -> 100% là Feature Component.
- Nếu component chỉ import React hooks thuần, thư viện UI (Radix, Tailwind, clsx) -> Rất có thể là Shared Component.
- Nhìn vào Props:
- Nếu Props quá cụ thể (VD: fabricId, customerData) -> Feature.
- Nếu Props rất chung chung (VD: title, items, isOpen, onConfirm) -> Shared.
Việc tuân thủ nghiêm ngặt ranh giới này giúp dự án không bị tình trạng "mớ bòng bong" (spaghetti code) khi số lượng màn hình tăng lên đến hàng chục, hàng trăm trong các hệ thống ERP.
Tags:
vinhphat-erp