Các hướng dẫn phù hợp cho cả dự án mới và hiện tại.
1# Hướng dẫn chung cho các dự án React/Next.js23> Mục đích: Các quy tắc chung để phát triển các dự án khác nhau với React + TypeScript, Next.js + TypeScript và Tailwind CSS.4> Cách sử dụng: Đặt tệp này vào thư mục gốc của dự án mới dưới dạng `AGENTS.md`, `CLAUDE.md` hoặc `PROJECT_RULES.md` hoặc sử dụng tệp này làm bộ hướng dẫn cơ bản cho tác nhân AI.5> Quan trọng: Những hướng dẫn này không chứa các quy tắc dành riêng cho sản phẩm. Giữ mọi thứ liên quan đến một dự án riêng lẻ trong một tệp `PROJECT_RULES.md` riêng biệt.67---89# 1. Nguyên tắc cốt lõi1011Xây dựng một ứng dụng sẵn sàng sản xuất chứ không phải một tập hợp các thành phần bị ngắt kết nối.1213Luôn làm theo trình tự sau:14151. Xem lại cấu trúc dự án hiện tại, `package.json`, định tuyến, nguyên gốc giao diện người dùng, cửa hàng, hook, lược đồ và quy tắc dự án.162. Tìm các hành động, trợ giúp, lược đồ và thành phần hiện có có thể được sử dụng lại.173. Xác định thay đổi nhỏ nhất cần thiết cho nhiệm vụ.184. Duy trì hành vi hiện có.195. Triển khai từng tính năng mới từ đầu đến cuối: mô hình, xác thực, giao diện người dùng, lưu trữ/nhập/xuất, các trường hợp biên và xác minh.206. Thực hiện các cuộc kiểm tra liên quan và báo cáo kết quả một cách trung thực.2122Không thêm các phần phụ thuộc, trừu tượng, kho lưu trữ toàn cầu hoặc lớp kiến trúc trừ khi chúng thực sự cần thiết.23Sử dụng `shadcn/ui` theo mặc định cho công việc giao diện người dùng. Không thêm bộ giao diện người dùng khác lên trên nó mà không có lý do rõ ràng.2425---2627# 2. Lựa chọn giữa React và Next.js2829Sử dụng Next.js khi dự án cần:3031- lộ trình;32- SEO;33- Thành phần SSR / Máy chủ;34- Hành động của máy chủ;35- Trình xử lý tuyến đường / tuyến API;36- xác thực;37- truy cập cơ sở dữ liệu;38- biến môi trường riêng tư;39- xuất bản nội dung.4041Sử dụng React + Vite khi:4243- ứng dụng hoàn toàn nằm ở phía máy khách;44- SEO là không cần thiết;45- đó là một công cụ cục bộ, trang tổng quan, trình chỉnh sửa, bảng quản trị hoặc giao diện người dùng giống máy tính để bàn;46- máy chủ đã tồn tại như một dịch vụ riêng biệt.4748Đừng chọn Next.js đơn giản vì nó phổ biến. Không thêm Redux, Zustand, React Query, thư viện biểu mẫu hoặc bộ giao diện người dùng khác mà không có lý do cụ thể.4950---5152# 3. Ngăn xếp và kiểm tra mặc định5354Sử dụng như sau theo mặc định:5556- Phản ứng;57- TypeScript ở chế độ nghiêm ngặt;58- CSS gió giật;59- `shadcn/ui` là phương pháp giao diện người dùng bắt buộc để có thiết kế gọn gàng và phát triển giao diện nhanh chóng;60- Lucide React hoặc thư viện biểu tượng được cấu hình shadcn hiện tại sử dụng;61- ESLint;62- người trợ giúp `cn()` được chia sẻ;63- xác nhận thời gian chạy cho dữ liệu bên ngoài;64- các phần tử HTML có thể truy cập được.6566Sử dụng `shadcn/ui` làm nguồn chính của giao diện người dùng gốc: nút, đầu vào, lựa chọn, hộp thoại, trang tính, danh sách thả xuống, chú giải công cụ, tab, băng chuyền, thẻ, huy hiệu, khung, vùng cuộn và các thành phần bắt buộc khác. Chỉ tạo các bản gốc tùy chỉnh khi shadcn không cung cấp thành phần phù hợp hoặc khi dự án đã có bản gốc cục bộ ổn định.6768Đối với MVP, trước tiên hãy bắt đầu với dữ liệu mô phỏng/JSON/localStorage và xác thực luồng người dùng cục bộ. Thêm phần phụ trợ, cơ sở dữ liệu, thanh toán, xác thực và tích hợp bên ngoài lần cuối khi giao diện người dùng, mô hình và quy trình rõ ràng.6970Ở mức tối thiểu, hãy chạy các lệnh này sau khi thay đổi mã:7172```bash73npm run typecheck74npm run lint75npm run build76```7778Đừng cho rằng dự án hoạt động nếu các lệnh này không được chạy hoặc hoàn thành có lỗi.7980---8182#4. Kiến trúc8384Đối với các dự án Next.js dự kiến sẽ phát triển, hãy giữ mã nguồn bên trong `src/` theo mặc định: `src/app`, `src/components`, `src/lib`, `src/data`, `src/hooks` và `src/features`. Giữ các thư mục và tệp hỗ trợ cấp gốc (`public`, tệp cấu hình, tệp khóa và README) trong thư mục gốc của dự án.8586Đối với các dự án nhỏ, cấu trúc sau được chấp nhận:8788```text89src/90 app/ or pages/91 components/92 features/93 lib/94 shared/95```9697Đối với các dự án vừa và lớn, hãy sử dụng cách tiếp cận giống FSD:9899```text100src/101 app/ # bootstrap, providers, layouts, routes102 views/ # page-level composition103 widgets/ # large UI blocks104 features/ # user workflows105 entities/ # domain model106 shared/ # generic helpers, config, thin wrappers around shadcn/ui107```108109Hướng nhập khẩu:110111```text112app/views -> widgets -> features -> entities -> shared113```114115Đừng:116117- nhập `widgets` vào `features`;118- đặt logic nghiệp vụ vào `shared`;119- biến `shared/lib` thành bãi rác cho những chức năng không liên quan;120- logic đột biến trùng lặp trên nhiều thành phần UI;121- sử dụng tính năng nhập sâu vào phần bên trong của mô-đun khác khi mô-đun đó hiển thị API công khai.122123---124125# 5. API công khai126127Mọi tính năng, thực thể hoặc thư mục giao diện người dùng dùng chung phải hiển thị API công khai rõ ràng thông qua `index.ts` khi mô-đun được sử dụng bên ngoài. Đối với các nguyên thủy shadcn, API công khai thường tồn tại trong `components/ui/*` hoặc lớp giao diện người dùng cục bộ của dự án.128129Tốt:130131```ts132import { createTask } from "@/features/create-task";133```134135Xấu:136137```ts138import { createTask } from "@/features/create-task/model/createTask";139```140141Ngoại lệ: mã nội bộ trong cùng một tính năng hoặc thực thể.142143---144145# 6. Bản đánh chữ146147Yêu cầu:148149- bật `strict: true`;150- không sử dụng `any` ngoại trừ mã có khả năng tương tác riêng biệt;151- không ẩn các lỗi loại với các xác nhận `as`;152- sử dụng các công đoàn phân biệt đối xử cho trạng thái phức tạp;153- xác thực JSON thời gian chạy bằng một lược đồ;154- không tạo nhiều loại giống nhau mà không có lý do chính đáng.155156Loại trạng thái ví dụ:157158```ts159type LoadState<T> =160 | { status: "idle" }161 | { status: "loading" }162 | { status: "success"; data: T }163 | { status: "error"; message: string };164```165166---167168# 7. Trạng thái và hiệu ứng phản ứng169170Lưu trữ trạng thái nơi nó thực sự thuộc về:171172| Loại trạng thái | Nơi lưu trữ nó |173| ------------ | ---------------------------------------------------------------------- |174| Giao diện người dùng cục bộ | `useState`, `useReducer` |175| Trạng thái URL | tham số tuyến đường/tìm kiếm |176| Trạng thái máy chủ | kết xuất máy chủ hoặc lớp bộ đệm/truy vấn |177| Trạng thái biểu mẫu | móc/thư viện biểu mẫu |178| Giao diện người dùng toàn cầu | một cửa hàng nhỏ khi cần thiết |179| Trạng thái miền | thực thể/lưu trữ khi trạng thái được chia sẻ trên nhiều luồng |180181Không đặt những thứ sau vào cửa hàng toàn cầu:182183- trạng thái di chuột;184- trạng thái của một lần thả xuống;185- giá trị dự thảo của một đầu vào;186- trạng thái của một phương thức duy nhất;187- tab được chọn tạm thời của một thành phần.188189Sử dụng `useEffect` để đồng bộ hóa với hệ thống bên ngoài:190191- API trình duyệt;192- bộ tính giờ;193- đăng ký;194- cửa hàng bên ngoài;195- Tích hợp DOM.196197Không sử dụng `useEffect` cho các giá trị dẫn xuất.198199Xấu:200201```tsx202const [fullName, setFullName] = useState("");203204useEffect(() => {205 setFullName(` `);206}, [firstName, lastName]);207```208209Tốt:210211```tsx212const fullName = ` `;213```214215---216217# 8. Ranh giới của Next.js218219Trong Bộ định tuyến ứng dụng, các thành phần theo mặc định là Thành phần máy chủ.220221Chỉ thêm `"use client"` khi bạn cần:222223- xử lý sự kiện;224- nhà nước địa phương;225- các hiệu ứng;226- `window`, `document` hoặc `localStorage`;227- kéo và thả;228- `contenteditable`;229- thư viện chỉ dành cho khách hàng.230231Không biến toàn bộ bố cục thành Thành phần khách hàng mà không có nhu cầu rõ ràng.232233Mã chỉ dành cho máy chủ bao gồm:234235- truy cập cơ sở dữ liệu;236- xác thực;237- ứng dụng khách API riêng tư;238- các biến môi trường bí mật;239- webhook;240- kiểm tra truy cập.241242Không bao giờ nhập mô-đun chỉ dành cho máy chủ vào Thành phần máy khách.243244---245246# 9. Xác thực và di chuyển thời gian chạy247248Xác thực tất cả dữ liệu bên ngoài tại ranh giới:249250- cơ quan yêu cầu;251- dữ liệu biểu mẫu;252- Tham số URL/tìm kiếm;253- tập tin đã tải lên;254- JSON đã nhập;255- dữ liệu localStorage/IndexedDB;256- phản hồi từ các API bên ngoài.257258Khi thêm trường mô hình mới, hãy cập nhật toàn bộ vòng đời:2592601. Kiểu TypeScript.2612. Lược đồ thời gian chạy.2623. Giá trị gốc/mặc định.2634. Trình phân tích cú pháp/di chuyển dữ liệu cũ.2645. Người trợ giúp chuẩn hóa.2656. Xuất nhập khẩu.2667. Lập chỉ mục tìm kiếm/lọc, nếu trường có thể tìm kiếm được.2678. Hoàn tác/làm lại ảnh chụp nhanh, nếu người dùng có thể chỉnh sửa trường này.2689. Giao diện người dùng để tạo, chỉnh sửa và xóa trường.26910. Vỏ và kiểm tra cạnh.270271Ví dụ:272273```ts274return {275 ...item,276 status: item.status ?? "active",277 tags: normalizeTags(item.tags),278 dueDate: normalizeDate(item.dueDate),279};280```281282Không chỉ thêm trường mô hình trong giao diện người dùng.283284---285286# 10. Biểu mẫu287288Mỗi hình thức phải bao gồm:289290- một lược đồ xác nhận;291- lỗi trường;292- trạng thái gửi/tải;293- nút gửi bị vô hiệu hóa trong khi gửi;294- bảo vệ chống lại việc gửi trùng lặp;295- trạng thái lỗi;296- hành vi thành công;297- hành vi đặt lại/dự thảo, khi có thể.298299Biểu mẫu không hoàn chỉnh nếu nó chỉ hoạt động khi yêu cầu thành công hoàn hảo.300301---302303# 11. shadcn/ui và Giao diện người dùng được chia sẻ304305Sử dụng `shadcn/ui` theo mặc định để xây dựng giao diện rõ ràng, nhất quán một cách nhanh chóng.306307Quy tắc:308309- trước tiên hãy kiểm tra xem thành phần được yêu cầu có tồn tại trong sổ đăng ký shadcn hay không;310- thêm các thành phần shadcn thông qua CLI hoặc phương pháp cục bộ đã được thiết lập của dự án;311- không tạo Nút, Đầu vào, Phương thức, Thả xuống, Chú giải công cụ, Tab hoặc Thẻ tùy chỉnh nếu shadcn đã bao gồm trường hợp sử dụng;312- điều chỉnh các thành phần shadcn thông qua `className`, các biến thể và thành phần thay vì sao chép các thành phần tương tự;313- giữ các thành phần kinh doanh tách biệt với các thành phần nguyên thủy: `components/marketplace`, `features/*/ui`, `widgets/*` hoặc `entities/*/ui`;314- chỉ giữ lại các phần tử gốc shadcn và các trình bao bọc mỏng có thể tái sử dụng trong `components/ui` hoặc `shared/ui`;315- không đặt các thành phần kinh doanh dành riêng cho sản phẩm ở đó;316- nếu shadcn không cung cấp thành phần, hãy tạo một trình bao bọc cục bộ tối thiểu phù hợp với cấu hình shadcn hiện tại.317318Bộ cơ sở các thành phần shadcn cho giao diện năng suất:319320```text321button322input323select324textarea325checkbox326switch327dialog328sheet329dropdown-menu330popover331tooltip332tabs333card334badge335avatar336separator337scroll-area338skeleton339carousel340accordion341collapsible342hover-card343```344345Đối với các luồng thị trường, trò chuyện và hỗ trợ, hãy lập kế hoạch cho các thành phần shadcn mới hơn này:346347```text348message349message-scroller350attachment351marker352```353354Luôn sử dụng `cn()`:355356```ts357export function cn(...values: Array<string | false | null | undefined>) {358 return values.filter(Boolean).join(" ");359}360```361362---363364#12. Chọn bề mặt giao diện người dùng phù hợp365366Trước khi thêm một công cụ mới, hãy chọn bề mặt phù hợp:367368| Kích thước tính năng | Vị trí | Ví dụ |369| ---------------------------------- | --------------------------------- | ----------------------------------- |370| 1-5 cài đặt nhanh | menu ngữ cảnh/thả xuống/popover | trạng thái, ngày đến hạn, thẻ |371| 5-12 cài đặt được nhóm | cửa sổ bật lên được chia nhỏ, có thể cuộn | thuộc tính thực thể, bộ lọc nhỏ gọn |372| tập dữ liệu lớn hoặc hành động hàng loạt | thanh bên / ngăn kéo | bộ lọc, bảng công cụ |373| hình thức phức tạp hoặc hành động nguy hiểm | phương thức | xác nhận nhập/xuất, xóa |374| không gian làm việc cố định | chế độ xem/trang/widget chuyên dụng | bảng điều khiển, lịch, trình soạn thảo |375376Luật lệ:377378> Nếu thỉnh thoảng sử dụng một điều khiển, hãy giữ nó trong menu.379> Nếu điều khiển được sử dụng liên tục, hãy để nó hiển thị trên bề mặt chính.380> Nếu điều khiển phức tạp và dài, hãy di chuyển nó sang thanh bên hoặc phương thức.381382Đừng biến một nhóm điều khiển nhỏ thành một thẻ lớn trên trang. Trong giao diện năng suất, điều này gây lãng phí không gian quý giá.383384---385386# 13. Giao diện người dùng nhỏ gọn dành cho Người chỉnh sửa, Trang tổng quan và Không gian làm việc387388Trong các ứng dụng năng suất, nội dung chính phải luôn là trọng tâm.389390Yêu cầu:391392- tiêu đề, nội dung, bảng hoặc người biên tập không được bị các nút điều khiển phụ đẩy xuống;393- thuộc tính thực thể thường mở từ nút biểu tượng bên cạnh tiêu đề;394- các nút cài đặt phải có `aria-label`;395- một trạng thái quan trọng có thể được hiển thị dưới dạng một huy hiệu nhỏ;396- hành động tạo/thêm phải xuất hiện trong ngữ cảnh rõ ràng;397- các luồng nặng về thanh bên phải bao gồm trình đơn hoặc trình chuyển đổi thân thiện với thiết bị di động;398- không làm cho công cụ năng suất trông giống như một trang đích.399400Xấu:401402```tsx403404 <Select>Status</Select>405 <Select>Task</Select>406 <Input>Date</Input>407 <Input>Tags</Input>408</LargePropertiesCard>409```410411Tốt:412413```tsx414415 <TitleInput />416 <PropertiesMenu />417</TitleRow>418```419420---421422# 14. Lớp phủ, Menu thả xuống, Cửa sổ bật lên và Menu ngữ cảnh423424Mỗi menu phải hoạt động như một lớp phủ thực sự.425426Quy tắc:427428- nếu một menu có thể mở rộng ra ngoài vùng chứa của nó, hãy hiển thị nó thông qua `createPortal(..., document.body)`;429- sử dụng `position: fixed` hoặc công cụ trợ giúp định vị đáng tin cậy;430- đặt `z-index` rõ ràng;431- sử dụng `backgroundColor` mờ đục;432- không chỉ dựa vào nền `bg-black/50` mờ hoặc mờ;433- thêm đường viền, vòng hoặc bóng;434- đặt `max-height` và `overflow-y-auto`;435- đóng vào `Escape`;436- đóng khi nhấp / chạm bên ngoài;437- ngăn văn bản trang hiển thị xuyên qua hoặc hiển thị trên menu;438- trạng thái di chuột và hoạt động không được thay đổi kích thước của vật phẩm.439440Kiểu lớp phủ tối thiểu:441442```tsx443<div444 role="menu"445 className="rounded-2xl border p-2 shadow-2xl"446 style="#151a21",447 boxShadow: "0 24px 70px rgb(0 0 0 / 78%)",448 isolation: "isolate",449 zIndex: 1000,450>451 ...452</div>453```454455Nếu nền menu không hiển thị chính xác hoặc nội dung xuất hiện phía trên nó, hãy kiểm tra:456457- cổng thông tin;458- `position`;459- `z-index`;460- bối cảnh xếp chồng cha mẹ;461- `isolation`;462- độ mờ/nền;463- tràn/cắt bớt cha mẹ.464465---466467#15. Danh sách tùy chọn trong Menu468469Danh sách nhiệm vụ, dự án, người dùng, thẻ hoặc các tùy chọn khác trong menu không được trông giống như một bức tường văn bản dày đặc.470471Đối với mục hai dòng:472473- sử dụng `min-height` có kích thước 40-44px;474- bao gồm `gap` giữa biểu tượng, văn bản và dấu kiểm;475- sử dụng khoảng đệm dọc như `py-1.5`;476- đặt tiêu đề và siêu dữ liệu có chiều cao dòng khác nhau;477- thêm `mt-0.5` giữa tiêu đề và siêu dữ liệu;478- áp dụng `min-w-0` cho phần tử cha chứa văn bản;479- áp dụng `truncate` cho tiêu đề và siêu dữ liệu;480- áp dụng `shrink-0` cho dấu kiểm và biểu tượng.481482Ví dụ:483484```tsx485<button className="flex min-h-11 items-center gap-2.5 rounded-lg px-2.5 py-1.5">486 <span className="min-w-0 flex-1">487 <span className="block truncate font-medium leading-5"></span>488 <span className="mt-0.5 block truncate text-xs leading-4 text-muted">489 {meta}490 </span>491 </span>492 {isActive ? <Check className="shrink-0" /> : null}493</button>494```495496---497498# 16. Văn bản dài và tràn499500Bất kỳ văn bản nào do người dùng cung cấp đều có thể chứa một từ dài không có dấu cách.501502Dành cho người chỉnh sửa, phần tử `contenteditable`, Markdown, tiêu đề thẻ và nhận xét:503504- sử dụng `min-w-0` trên các phần tử con flex/lưới;505- sử dụng các tiện ích Tailwind hiện tại để gói các từ dài;506- trong các phiên bản Tailwind mới hơn, `break-words` có thể được viết là `wrap-break-word`;507- kiểm tra tài liệu về phiên bản Tailwind hiện tại của dự án trước khi sử dụng các lớp gói, tràn, bọc văn bản, lưới, giãn cách hoặc giá trị tùy ý;508- nếu một phần tử nằm trong vùng chứa linh hoạt và văn bản dài phá vỡ chiều rộng của nó, hãy kiểm tra xem `wrap-anywhere` có phù hợp hay không;509- sử dụng `truncate` cho các dòng ngắn trong thẻ;510- bọc nội dung văn bản thay vì cho phép tràn ngang;511- văn bản không được hiển thị trên menu, cửa sổ bật lên hoặc phương thức;512- kiểm tra với một chuỗi dài không chứa khoảng trắng.513514Đối với khối có thể chỉnh sửa:515516```tsx517className = "min-w-0 wrap-break-word whitespace-pre-wrap";518```519520Nếu dự án sử dụng phiên bản Tailwind cũ hơn và không có `wrap-break-word`, hãy kiểm tra phiên bản Tailwind đã cài đặt và tài liệu chính thức hoặc ghi chú phiên bản, sau đó sử dụng phiên bản tương đương được hỗ trợ: `break-words`, một giá trị tùy ý hoặc thuộc tính CSS.521522Đối với huy hiệu:523524```tsx525className = "inline-flex whitespace-nowrap";526```527528Huy hiệu không được nén văn bản theo chiều dọc. Nếu không vừa, hãy chuyển nó sang dòng mới hoặc sử dụng `truncate` với chiều rộng rõ ràng, dễ hiểu.529530---531532# 17. Tailwind CSS: Xác minh tên lớp hiện tại533534Tác nhân AI phải kiểm tra phiên bản Tailwind được cài đặt trong dự án trước khi sử dụng các lớp mới hoặc có khả năng phụ thuộc vào phiên bản.535536Quá trình:5375381. Kiểm tra `package.json` và tệp khóa.5392. Xác định phiên bản chính của Tailwind.5403. Nếu một lớp có thể khác nhau giữa các phiên bản, hãy kiểm tra tài liệu chính thức để biết phiên bản chính xác đó.5414. Không thay thế các lớp một cách máy móc khi chưa xác minh.5425. Khi sử dụng một giá trị tùy ý, hãy xác nhận rằng giá trị đó có trong kết quả xây dựng.543544Đặc biệt chú ý đến:545546- `break-words` / `wrap-break-word` / `wrap-anywhere`;547- `text-wrap`, `text-balance` và `text-pretty`;548- `overflow-*`;549- `size-*`;550- màu tùy ý như `bg-[#151a21]`;551- bóng tùy ý;552- mẫu lưới tùy ý;553- tên lớp năng động.554555Đừng xây dựng các lớp Tailwind động như thế này:556557```tsx558const color = "red";559return <div className={`bg--500`} />;560```561562Tailwind có thể không phát hiện được lớp đó trong quá trình xây dựng. Sử dụng bản đồ:563564```tsx565const colorClassName = {566 danger: "bg-red-500",567 success: "bg-emerald-500",568};569```570571Nếu nền lớp phủ quan trọng không được phụ thuộc vào kết quả xây dựng của Tailwind thì việc sử dụng `style.backgroundColor` nội tuyến có thể được chấp nhận.572573---574575# 18. Bố cục và thu gọn thanh bên576577Việc thu gọn thanh bên hoặc ngăn không được làm thay đổi chiều cao của trang hoặc để lại khối trống.578579Quy tắc:580581- vỏ ứng dụng: `h-dvh min-h-dvh overflow-hidden`;582- khu vực nội bộ: `flex min-h-0 flex-1 overflow-hidden`;583- chỉ bật cuộn trên vùng thích hợp với `overflow-y-auto`;584- khi thu gọn, thay đổi chiều rộng/cơ sở uốn cong thay vì chiều cao;585- thanh bên thu gọn phải có chiều rộng ổn định;586- cung cấp khả năng kiểm soát rõ ràng để khôi phục thanh bên;587- các hành động phá hoại hoặc sáng tạo không được duy trì dưới dạng các nút biệt lập mà không có ngữ cảnh;588- các tùy chọn có thể được lưu giữ trong localStorage.589590Ví dụ:591592```tsx593<main className="flex h-dvh min-h-dvh flex-col overflow-hidden">594 <div className="flex min-h-0 flex-1 overflow-hidden">595 <Sidebar className="h-full min-h-0 shrink-0" />596 <section className="min-h-0 flex-1 overflow-y-auto" />597 </div>598</main>599```600601---602603# 19. API trình duyệt và localStorage604605Trong Next.js, API trình duyệt chỉ khả dụng trong Thành phần máy khách.606607Quy tắc:608609- tệp sử dụng `localStorage`, `window`, `document`, kéo và thả hoặc `contenteditable` phải bao gồm `"use client"`;610- không đọc `localStorage` trong Thành phần Máy chủ;611- không gây ra lỗi hydrat hóa với các giá trị ban đầu khác nhau;612- gói các hoạt động lưu trữ trong `try/catch`;613- lỗi lưu trữ không được làm hỏng giao diện người dùng;614- xác minh các tùy chọn giao diện người dùng được duy trì sau khi tải lại;615- quá trình xây dựng không được bị lỗi với `window is not defined`.616617Ví dụ:618619```tsx620const toggle = useCallback(() => {621 setIsCollapsed((current) => {622 const next = !current;623624 try {625 window.localStorage.setItem(KEY, next ? "true" : "false");626 } catch {627 // UI still works without browser storage.628 }629630 return next;631 });632}, []);633```634635Xác minh rằng:636637- trạng thái mặc định hoạt động với bộ nhớ trống;638- tải lại bảo tồn trạng thái;639- chế độ riêng tư hoặc lỗi lưu trữ không làm vỡ màn hình;640- quá trình xây dựng không bị lỗi với `window is not defined`.641642---643644# 20. Mối quan hệ giữa các công cụ645646Nếu một thực thể được liên kết với một thực thể khác thì mối quan hệ phải là thực tế:647648- lưu trữ nó trong mô hình;649- hiển thị nó trong giao diện người dùng;650- nhấp vào nó sẽ mở thực thể được liên kết;651- khi tạo thực thể liên quan, hãy lưu mối quan hệ ngay lập tức;652- duy trì mối quan hệ trong quá trình xuất nhập khẩu;653- đưa mối quan hệ vào hành vi tìm kiếm/lọc khi hữu ích;654- nếu thực thể liên quan bị xóa, hãy hiển thị dự phòng trong giao diện người dùng.655656Không tạo nút "Liên kết" trang trí nếu mối quan hệ không được duy trì.657658---659660# 21. Hoạt động miền thống nhất661662Mỗi hoạt động của người dùng phải có một nguồn sự thật duy nhất.663664Đừng:665666- tạo một thực thể theo một cách từ menu dấu gạch chéo;667- tạo nó theo cách khác từ thanh công cụ;668- bỏ qua xác nhận từ bảng lệnh;669- logic đột biến trùng lặp trong menu ngữ cảnh.670671Thay vì:672673- giữ hoạt động tên miền ở một nơi;674- yêu cầu các thành phần giao diện người dùng gọi thao tác đó;675- sử dụng cùng một xác nhận và các ràng buộc cho mọi điểm vào.676677---678679# 23. Khả năng tiếp cận680681Yêu cầu:682683- sử dụng `<button>` cho các hành động;684- sử dụng `<a>` để điều hướng;685- thêm `aria-label` vào các nút chỉ có biểu tượng;686- cung cấp nhãn cho đầu vào;687- hiển thị trạng thái lấy nét rõ ràng;688- hỗ trợ điều hướng bàn phím;689- đóng các chế độ và cửa sổ bật lên trên `Escape`;690- đóng cửa sổ bật lên khi nhấp chuột bên ngoài;691- sử dụng bẫy lấy nét trong các phương thức;692- không sử dụng màu sắc làm cách duy nhất để truyền đạt ý nghĩa;693- không thay thế `<button>` bằng ``.694695---696697# 24. Trạng thái tải, trống và lỗi698699Màn hình dựa trên dữ liệu phải tính đến:700701- đang tải;702- thành công;703- trạng thái trống rỗng;704- sự cho phép bị từ chối;705- lỗi mạng;706- lỗi máy chủ;707- thử lại.708709Màn hình trống không có lời giải thích là lỗi.710711---712713#25. Bảo mật714715Yêu cầu:716717- chỉ giữ bí mật trên máy chủ;718- sử dụng xác nhận thời gian chạy;719- thực thi kiểm soát truy cập trên máy chủ;720- xác thực loại và kích thước tệp MIME;721- vệ sinh HTML do người dùng cung cấp;722- không sử dụng `dangerouslySetInnerHTML` mà không có chất khử trùng;723- không đăng nhập mã thông báo hoặc dữ liệu cá nhân;724- không tin cậy các giá trị `role` hoặc `userId` do trình duyệt cung cấp.725726---727728#26. Hiệu suất729730Đo lường trước, sau đó tối ưu hóa.731732Sử dụng:733734- nhập động cho các mô-đun soạn thảo, biểu đồ, bản đồ và PDF nặng;735- tối ưu hóa hình ảnh;736- ảo hóa cho các danh sách lớn;737- bảo vệ yêu cầu hủy bỏ/cũ để tìm kiếm;738- bộ chọn để giảm hiển thị lại.739740Không thêm ghi nhớ mà không có lý do.741742---743744#27. Kiểm tra thiết kế với nội dung thực tế745746Để được hướng dẫn thêm về chất lượng giao diện, bạn có thể tham khảo:747748- https://jakub.kr/skills/make-interfaces-feel-better749750Tài nguyên này hữu ích khi đánh bóng kiểu chữ, trạng thái di chuột, bóng, đường viền, khoảng cách, căn chỉnh quang học, tương tác vi mô và cảm giác tổng thể của giao diện.751752Trước khi hoàn thành một tác vụ UI, hãy kiểm tra nó bằng:753754- một từ dài không có dấu cách;755- một tựa đề dài bằng tiếng Nga;756- một tiêu đề ngắn;757- một tiêu đề trống;758- nhiều thẻ;759- một danh sách dài/tên danh mục;760- nhiều tùy chọn trong danh sách thả xuống;761- trạng thái hoạt động và không hoạt động;762- một ngày và một ngày bị thiếu.763764Xác minh rằng:765766- không có gì trùng lặp;767- lớp phủ bao phủ nội dung cơ bản;768- văn bản không hiển thị qua menu;769- huy hiệu không nén văn bản theo chiều dọc;770- các yếu tố không chen chúc nhau;771- thanh cuộn không che phần văn bản quan trọng;772- trạng thái di chuột và tiêu điểm dễ đọc;773- chiều rộng của máy tính để bàn và thiết bị di động đều trông chính xác.774775---776777# 28. Kiểm tra sau khi thay đổi778779Sau khi thay đổi mã, hãy chạy:780781```bash782npm run typecheck783npm run lint784npm run build785```786787Nếu giao diện người dùng đã được thay đổi:788789- mở trang trong trình duyệt;790- hoàn thành luồng người dùng chính;791- kiểm tra tương tác bàn phím và chuột;792- kiểm tra `Escape` và hành vi nhấp chuột bên ngoài;793- thử tải lại;794- kiểm tra văn bản dài;795- kiểm tra chiều rộng khung nhìn trên thiết bị di động;796- chụp ảnh màn hình nếu lớp trực quan thay đổi.797798Nếu không thể xác minh trình duyệt, hãy nói rõ ràng như vậy. Không hiển thị `typecheck` dưới dạng xác minh trực quan.799800---801802# 29. Git và Cây làm việc803804Trước khi thực hiện thay đổi, hãy kiểm tra trạng thái hiện tại:805806```bash807git status --short808```809810Quy tắc:811812- không hoàn nguyên những thay đổi của người khác mà không có yêu cầu rõ ràng;813- không sử dụng các lệnh phá hoại mà không có sự cho phép rõ ràng;814- không thực hiện tái cấu trúc không liên quan;815- không tự động cam kết trừ khi người dùng yêu cầu bạn;816- không thay đổi kết thúc dòng hoặc định dạng lại toàn bộ dự án một cách không cần thiết.817818---819820# 30. Báo cáo cuối cùng821822Trong câu trả lời cuối cùng, hãy nêu:823824- những gì đã thay đổi;825- tập tin nào là quan trọng;826- kiểm tra nào đã được thực hiện;827- những gì không thể được xác minh;828- những rủi ro nào vẫn còn.829830Giữ báo cáo ngắn gọn và trung thực.831