สัปดาห์ที่ 3

Vite + React: ตั้งค่าโปรเจกต์, JSX & Component เบื้องต้น

CLO3
📖 ทฤษฎี

Vite คืออะไร

Vite (อ่านว่า "วีต") เป็น Build Tool รุ่นใหม่สำหรับพัฒนา Web Application สร้างโดย Evan You ผู้สร้าง Vue.js จุดเด่นหลักคือความเร็วในการ Start Dev Server และ Hot Module Replacement (HMR) ที่แทบทันทีเมื่อแก้ไขไฟล์

เปรียบเทียบกับ Create React App (CRA) ที่หลายคนอาจเคยใช้:

  • CRA — ใช้ webpack ที่ต้อง bundle ทุกไฟล์ก่อน dev server จึงช้ามากในโปรเจกต์ใหญ่
  • Vite — ใช้ native ES Modules ของ browser และ esbuild (เขียนด้วย Go) ทำให้ Start Server เร็วกว่า CRA 10–100 เท่า

HMR (Hot Module Replacement) คือความสามารถในการอัปเดตเฉพาะโมดูลที่เปลี่ยนแปลง โดยไม่ต้อง Reload หน้าทั้งหมด ทำให้ state ของแอปยังคงอยู่ขณะพัฒนา

โครงสร้างโปรเจกต์ Vite + React:

  bookeasy/
  ├── public/          ← ไฟล์ static (favicon, images)
  ├── src/
  │   ├── components/  ← React Components
  │   ├── App.jsx      ← Root Component
  │   ├── main.jsx     ← Entry point (ReactDOM.createRoot)
  │   └── index.css    ← Global styles
  ├── index.html       ← HTML template (Vite entry)
  ├── vite.config.js   ← Vite configuration
  └── package.json     ← Dependencies & npm scripts
          

npm scripts ที่ใช้บ่อยใน Vite project:

  • npm run dev — เปิด Dev Server พร้อม HMR ที่ http://localhost:5173
  • npm run build — Build สำหรับ Production สร้างไฟล์ใน dist/
  • npm run preview — Preview ไฟล์ที่ Build แล้วก่อน Deploy

JSX คืออะไร

JSX (JavaScript XML) เป็น Syntax Extension ของ JavaScript ที่ให้เขียน HTML-like markup ภายใน JavaScript ได้โดยตรง JSX ไม่ใช่ HTML จริง แต่ Vite/Babel จะ transform ให้กลายเป็น React.createElement() ที่ JavaScript เข้าใจ

  • ใช้ className แทน class — เพราะ class เป็น reserved keyword ใน JavaScript
  • ใช้ htmlFor แทน for — เช่นเดียวกัน for เป็น reserved keyword
  • ฝัง JavaScript ด้วย {} — ใส่ expression ใดก็ได้ภายใน curly braces เช่น {name}, {price * 1.07}
  • Tag ต้องปิดเสมอ — ต่างจาก HTML ที่ <img> ไม่ต้องปิด ใน JSX ต้องเป็น <img />
  • Return element เดียวเท่านั้น — ต้องห่อด้วย <div> หรือ Fragment <>...</>
หมายเหตุ

JSX ดูเหมือน HTML แต่ทำงานใน JavaScript context ทุก expression ใน {} ต้องคืนค่า ไม่ใช่ Statement เช่น ใช้ Ternary Operator (condition ? a : b) แทน if/else และใช้ array.map() แทน for loop

React Function Component และ Props

Function Component คือฟังก์ชัน JavaScript ที่ return JSX ชื่อ Component ต้องขึ้นต้นด้วยตัวพิมพ์ใหญ่ (เช่น ServiceCard, Header) เพื่อให้ React แยกแยะจาก HTML element ได้

Props (Properties) คือข้อมูลที่ส่งจาก Parent Component ไปยัง Child Component ทำงานคล้าย Parameter ของฟังก์ชัน ทำให้ Component นำกลับใช้ซ้ำได้ด้วยข้อมูลต่างกัน:

  • ส่ง props ด้วย syntax เหมือน HTML attribute: <ServiceCard name="ตัดผม" price={150} />
  • รับ props ใน Component ด้วย destructuring: function ServiceCard({ name, price }) {}
  • Props เป็น Read-only — Component ไม่ควรแก้ไข props ที่ได้รับ
  • Spread props: <ServiceCard {...service} /> ส่งทุก property ของ object
เคล็ดลับ — Naming Conventions

ไฟล์ Component ใช้ PascalCase เช่น ServiceCard.jsx, Header.jsx ชื่อ CSS class ใช้ kebab-case เช่น service-card, services-grid ส่วน JavaScript variables และ functions ใช้ camelCase

💻 โค้ดตัวอย่าง
terminal Bash
# ตั้งค่าโปรเจกต์ BookEasy
npm create vite@latest bookeasy -- --template react
cd bookeasy
npm install
npm run dev
# เปิด http://localhost:5173
src/components/ServiceCard.jsx JSX
// React Component เบื้องต้น — ServiceCard.jsx
function ServiceCard({ name, description, price, duration }) {
  return (
    <div className="service-card">
      <h3>{name}</h3>
      <p>{description}</p>
      <div className="service-info">
        <span>ราคา: {price} บาท</span>
        <span>เวลา: {duration} นาที</span>
      </div>
      <button>จองบริการนี้</button>
    </div>
  );
}

export default ServiceCard;
src/App.jsx JSX
// ใช้ Component ใน App.jsx
import ServiceCard from './components/ServiceCard';

const MOCK_SERVICES = [
  { id: 1, name: 'ตัดผมชาย', description: 'ตัดผมสไตล์เกาหลี/ยุโรป', price: 150, duration: 45 },
  { id: 2, name: 'นวดแผนไทย', description: 'นวดผ่อนคลาย 60 นาที', price: 400, duration: 60 },
  { id: 3, name: 'สปาหน้า', description: 'บำรุงผิวหน้า ลดรอยแดง', price: 600, duration: 90 },
];

function App() {
  return (
    <main>
      <h1>BookEasy — จองบริการออนไลน์</h1>
      <div className="services-grid">
        {MOCK_SERVICES.map(service => (
          <ServiceCard key={service.id} {...service} />
        ))}
      </div>
    </main>
  );
}

export default App;

🧪 ปฏิบัติการ Lab 2 — BookEasy: Scaffold โปรเจกต์ React

สร้าง Vite + React project สำหรับ BookEasy สร้าง Component โครงสร้างหลัก และทดสอบ render ด้วย mock data

ต่อยอดจาก Lab 1

เราสร้าง HTML/CSS static ไปแล้ว ตอนนี้จะ rebuild ด้วย React + Vite

1
สร้าง Vite + React project

Scaffold โปรเจกต์ React ใหม่ด้วย Vite template และทดสอบให้รันได้บน Dev Server

  • รัน npm create vite@latest bookeasy -- --template react
  • เข้าไปในโฟลเดอร์ด้วย cd bookeasy แล้วรัน npm install
  • ลบไฟล์ที่ Vite สร้างให้แต่ไม่ต้องการ: src/App.css และ src/assets/react.svg
  • ตรวจสอบว่า npm run dev เปิดได้ที่ http://localhost:5173
เกณฑ์การผ่าน

เปิด http://localhost:5173 แล้วเห็นหน้า Default Vite + React ไม่มี Error ใน Console

คำแนะนำ

หาก port 5173 ถูกใช้งานอยู่ Vite จะใช้ port ถัดไปอัตโนมัติ ให้สังเกตหมายเลข port ใน terminal และ npm run dev ต้องรันภายใน folder bookeasy/ ที่มีไฟล์ package.json

2
สร้าง Component โครงสร้าง

สร้าง Component หลักทั้งหมดและเชื่อมต่อใน App.jsx

  • สร้าง src/components/Header.jsx — แสดง Logo และ nav links
  • สร้าง src/components/Footer.jsx — แสดง copyright
  • สร้าง src/components/ServiceCard.jsx — รับ props: name, description, price, duration
  • แก้ไข src/App.jsx ให้ใช้ Header, Footer, ServiceCard พร้อม MOCK_SERVICES array
เกณฑ์การผ่าน

แต่ละไฟล์ export Component ได้ถูกต้อง App.jsx import และใช้งาน Component ทั้ง 3 ตัวได้ ไม่มี Error ใน Console และไม่มี TypeScript — ไฟล์ใช้นามสกุล .jsx ทั้งหมด

คำแนะนำ

สร้าง folder src/components/ ก่อน แล้วสร้างไฟล์แต่ละตัว ทุก Component ต้องมี export default และชื่อ Component ต้องขึ้นต้นด้วยตัวพิมพ์ใหญ่

3
ตรวจ render

ตรวจสอบว่าหน้าเว็บ render Component ครบถ้วนและไม่มี build error

  • ดูในเบราว์เซอร์ว่าหน้าแสดง Header, ServiceCard 3 ใบจาก mock data, และ Footer
  • ถ่ายภาพหน้าจอหน้า localhost:5173
  • รัน npm run build และตรวจสอบว่าไม่มี error ใน terminal
เกณฑ์การผ่าน

หน้าแสดง Header, 3 ServiceCard พร้อม name/description/price/duration จาก mock data, และ Footer รัน npm run build แล้วสำเร็จ ไม่มี error — ส่งภาพหน้าจอและไฟล์โค้ดให้อาจารย์

คำแนะนำ

หากเห็น ServiceCard is not defined ให้ตรวจสอบว่า import path ถูกต้อง เช่น import ServiceCard from './components/ServiceCard' (Vite ไม่ต้องใส่ .jsx ก็ได้)