🧩 Tư duy component và khởi tạo dự án với Vite

By Better Wise

Ở bài trước bạn đã dùng map, filter, reduce để biến một mảng dữ liệu thành một mảng mới gọn gàng. Bài này dùng đúng ý đó: một mảng khóa học sẽ được biến thành một danh sách các khối giao diện. Chỉ khác là thay vì tạo chuỗi HTML, ta tạo ra component.

Bạn sẽ làm được gì sau bài này

  • Nhìn một trang HTML quen thuộc và chỉ ra được các khối nên tách thành component.
  • Đặt tên component đúng quy ước và vẽ được cây component của một trang.
  • Tạo, cài dependency và chạy được dự án React bằng Vite, đọc được cấu trúc thư mục mặc định.

Từ một khối HTML đến cây component

Mở đầu bằng thứ bạn đã biết: một trang danh sách khóa học viết bằng HTML thuần.

<div class="page">
  <header class="site-header">Học React từ nền tảng</header>
  <main>
    <article class="course-card">
      <h3>ES6 thiết yếu</h3>
      <p>12 bài</p>
    </article>
    <article class="course-card">
      <h3>map, filter, reduce</h3>
      <p>8 bài</p>
    </article>
    <article class="course-card">
      <h3>Tư duy component</h3>
      <p>10 bài</p>
    </article>
  </main>
  <footer class="site-footer">© 2025</footer>
</div>

Tư duy component gồm 4 bước, làm đúng thứ tự này:

  1. Tìm khối lặp lại. Ba thẻ article.course-card giống hệt nhau về cấu trúc, chỉ khác dữ liệu. Đây là ứng viên số một: CourseCard.
  2. Tìm vùng bao quanh có vai trò riêng. Phần đầu trang là Header, phần chân trang là Footer, vùng chứa danh sách là CourseList.
  3. Đặt tên theo vai trò, không theo vị trí. CourseCard tốt hơn DivBenTrai2. Tên component luôn viết PascalCase, vì React dựa vào chữ hoa đầu tiên để phân biệt component với thẻ HTML có sẵn.
  4. Vẽ cây. Cây này chính là cách React nhìn trang của bạn.
flowchart LR
    App["📱<br/>App"] --> Header["🧭<br/>Header"]
    App --> CourseList["📚<br/>CourseList"]
    App --> Footer["📄<br/>Footer"]
    CourseList --> C1["🃏<br/>CourseCard"]
    CourseList --> C2["🃏<br/>CourseCard"]
    CourseList --> C3["🃏<br/>CourseCard"]

Điểm khác biệt cốt lõi so với HTML thuần: bạn không còn tự tay document.querySelector rồi sửa từng thẻ. Bạn mô tả giao diện ứng với dữ liệu, React so sánh và cập nhật DOM giúp bạn. Đó là lý do việc chia component quan trọng hơn việc nhớ cú pháp.

Note: Chưa cần biết JSX hay props ở bài này. Bây giờ chỉ cần nhìn giao diện và trả lời được: khối nào lặp lại, khối nào có vai trò riêng.

Bài tập nhanh 1

Với trang chi tiết khóa học gồm: tiêu đề khóa học, ảnh bìa, mô tả, danh sách 5 bài học (mỗi bài có số thứ tự, tên, thời lượng), nút "Đăng ký" và chân trang. Hãy liệt kê các component bạn sẽ tách và lý do.

Xem gợi ý

Gợi ý: CourseHeader (tiêu đề và ảnh bìa), CourseDescription, LessonItem (lặp 5 lần), LessonList (bao danh sách bài học), EnrollButton, Footer. Điểm quan trọng không phải số lượng mà là lý do: LessonItem lặp lại, EnrollButton có hành vi riêng, phần còn lại là vùng có vai trò rõ ràng.

Khởi tạo dự án React bằng Vite trong 5 bước

Vite là công cụ dựng dự án (build tool). Nó chạy dev server rất nhanh và có HMR (Hot Module Replacement): bạn sửa file, trình duyệt cập nhật ngay module đó, không tải lại cả trang.

  1. Kiểm tra Node.js: chạy node -v, nên dùng Node 18 trở lên
  2. Tạo dự án: npm create vite@latest khoa-hoc-app -- --template react
  3. Vào thư mục dự án: cd khoa-hoc-app, sau đó cài dependency: npm install
  4. Chạy dev server: npm run dev
  5. Mở http://localhost:5173 trên trình duyệt

Phần -- --template react nghĩa là: dấu -- kết thúc tham số của npm, phần còn lại được chuyển cho Vite. Nếu bỏ sót, Vite sẽ hỏi lại từ đầu bằng menu tương tác, vẫn ổn, chỉ mất thêm vài dòng lệnh.

Sau khi tạo xong, cấu trúc thư mục trông như sau:

khoa-hoc-app/
  index.html
  package.json
  vite.config.js
  src/
    main.jsx
    App.jsx
    App.css
    index.css
    assets/

Hai file bạn cần để ý ngay:

  • index.html có một thẻ <div id="root"></div>. Đây là điểm neo duy nhất.
  • src/main.jsx là nơi React được gắn vào điểm neo đó và render component gốc App. Mọi thứ bạn thấy trên trang đều nằm trong App.

Bài tập nhanh 2

Tạo dự án tên khoa-hoc-app, chạy dev server, mở trình duyệt. Sau đó sửa nội dung trong src/App.jsx thành một dòng chữ của riêng bạn, lưu file và quan sát. Ghi lại: bạn có phải bấm F5 không?

Xem gợi ý

Bạn không cần F5, HMR cập nhật ngay. Nếu không thấy thay đổi, kiểm tra ba điều: bạn đang sửa file trong src/ chứ không phải index.html, dev server còn chạy trong terminal, và bạn đang mở đúng cổng mà terminal in ra (Vite tự đổi sang 5174 nếu 5173 bận).

Luyện tập: chia giao diện cho dự án khoa-hoc-app

Đây là bài tập chính, làm trên giấy trước rồi mới mở trình soạn thảo.

Đề bài: Ứng dụng khoa-hoc-app có ba vùng: thanh trên cùng hiển thị tên ứng dụng và số khóa học đã đăng ký, vùng giữa là danh sách khóa học (mỗi khóa: tên, số bài, nhãn "Miễn phí" hoặc "Trả phí"), vùng dưới là tổng số khóa học đang hiển thị.

  1. Vẽ cây component ra giấy, tối đa 6 component.
  2. Với mỗi component, ghi một câu mô tả trách nhiệm duy nhất của nó.
  3. Chỉ ra khối nào là ứng viên lặp lại và dữ liệu nào sẽ thay đổi giữa các lần lặp (chưa cần viết code).
  4. Tạo dự án Vite, xoá phần nội dung mẫu trong src/App.jsx và thay bằng một khung đơn giản có ba vùng, mỗi vùng là một dòng chữ tạm. Mục tiêu là dựng đúng "bộ xương", không phải làm đẹp.

Gợi ý

Một đáp án hợp lý: App (bọc tất cả) chứa TopBar (tên ứng dụng, số đã đăng ký), CourseList (bao danh sách), CourseCard (một khóa, lặp lại), CourseSummary (tổng số khóa). Bốn component là đủ. Nếu bạn tách thêm FreeBadge ngay từ đầu thì không sai, nhưng tự hỏi: nó có được dùng ở nơi khác không? Nếu chưa, gộp vào CourseCard cho gọn.

Lỗi người mới hay gặp khi chia component và chạy Vite

Hiện tượng Nguyên nhân thường gặp Cách xử lý
Missing script: "dev" Chạy npm run dev ở thư mục cha, không phải thư mục dự án cd khoa-hoc-app rồi chạy lại
Cannot find module 'react' Chưa chạy npm install sau khi tạo dự án Chạy npm install trong thư mục dự án
Component không hiển thị Đặt tên chữ thường như courseCard, React hiểu là thẻ HTML lạ Đổi thành CourseCard
Sửa mãi không thấy đổi Đang sửa index.html hoặc file ngoài src/ Sửa trong src/App.jsx
Cổng 5173 báo bận Một dev server khác đang chạy Đọc log, Vite đã đổi cổng, hoặc tắt tiến trình cũ

Một lỗi về tư duy hay gặp hơn cả lỗi cú pháp: chia component quá vụn ngay từ đầu. Nếu mỗi div là một component, bạn sẽ có 15 file cho một trang nhỏ và không biết lỗi nằm ở đâu. Ngược lại, dồn cả trang vào App cũng khiến việc sửa một thẻ loạn theo. Mốc hợp lý là chia theo vai trò, không theo thẻ HTML.

Mẹo của người đi trước: chia vừa đủ, dựng dự án đúng ngay lần đầu

  • Tách component khi khối đó lặp lại từ 2 lần trở lên, hoặc khi nó có dữ liệu và hành vi riêng. Chưa có lý do thì để yên.
  • Bắt đầu từ một App lớn, chạy được đã, rồi tách dần. Tách sau luôn dễ hơn ghép lại.
  • Mỗi file một component chính, tên file trùng tên component (CourseCard.jsx). Người khác mở dự án sẽ tìm được ngay.
  • Giữ mỗi component dưới khoảng 100 dòng. Vượt mốc đó thường là dấu hiệu có 2 component đang bị gộp.
  • Vẽ cây component ra giấy mất 2 phút, tiết kiệm 20 phút sửa lại cấu trúc.
  • Ngay khi npm run dev chạy được, commit một lần. Mốc này giúp bạn quay lại dễ dàng nếu thử nghiệm sau đó làm hỏng cấu hình.

Bộ thẻ ôn tập nhanh

Front: Tư duy component là gì? Back: Chia giao diện thành các khối UI độc lập, có vai trò rõ ràng, thay vì thao tác DOM trực tiếp.

Front: Quy ước đặt tên component trong React? Back: PascalCase, ví dụ CourseCard.

Front: Vì sao component phải viết hoa chữ cái đầu? Back: React dựa vào chữ hoa để phân biệt component với thẻ HTML có sẵn.

Front: Lệnh tạo dự án React bằng Vite? Back: npm create vite@latest khoa-hoc-app -- --template react

Front: Lệnh chạy dev server của Vite? Back: npm run dev

Front: Vite mặc định phục vụ ở cổng nào? Back: 5173, và tự đổi cổng nếu cổng đó đang bận.

Front: File nào gắn ứng dụng React vào DOM? Back: src/main.jsx, render vào thẻ có id root trong index.html.

Front: Component gốc trong dự án Vite mặc định tên gì? Back: App, nằm trong src/App.jsx.

Front: Khi nào nên tách một component mới? Back: Khi khối UI lặp lại từ 2 lần trở lên, hoặc có dữ liệu và hành vi riêng.

Front: Vì sao không nên chia component quá vụn ngay từ đầu? Back: Tăng số file, khó lần ra lỗi; chỉ tách khi có lý do rõ ràng.

Front: Lỗi Missing script: "dev" thường do đâu? Back: Chạy lệnh ở sai thư mục, không phải thư mục dự án.

Front: npm install làm gì? Back: Cài các dependency khai báo trong package.json vào thư mục node_modules.

Front: HMR của Vite là gì? Back: Hot Module Replacement: cập nhật ngay module vừa sửa, không tải lại cả trang.

Chốt lại và bước tiếp theo

Ba điều đáng mang theo: giao diện là một cây component; tên component viết PascalCase và đặt theo vai trò; Vite lo phần dựng dự án để bạn tập trung vào việc chia khối.

Điền nhanh để tự kiểm tra:

  • Component trong React phải được đặt tên theo kiểu _____.
  • Lệnh tạo dự án React với Vite là _____.
  • Sau khi tạo dự án, cần chạy _____ để cài dependency.
  • Vite chạy dev server mặc định ở cổng _____.
  • React render ứng dụng vào thẻ có id _____ trong index.html.

Bài tiếp theo là buổi checkpoint của module: bạn sẽ ôn lại ES6, map/filter/reduce và tư duy component trong một loạt bài tập ngắn, rồi bước sang bài đầu tiên của module 2, nơi cây component vừa vẽ sẽ được viết thành JSX thật.