# Lab 11: React #1 - Basics & Components

## 🎯 วัตถุประสงค์

หลังจากทำ Lab นี้ เมื่อจบแล้ว นิสิตสามารถ

- สร้างโครงการ React ด้วย Vite
- เขียน JSX และเข้าใจกฎต่างๆ
- สร้าง Function Components ที่ซ้ำใช้ได้
- ส่งและรับข้อมูลผ่าน Props
- ใช้ .map() เพื่อแสดงรายการข้อมูล

---

## 📋 ส่วนที่ 1: Setup & JSX

### ขั้นตอน 1.1: สร้างโปรเจก React ใหม่

```bash
# สร้างโฟลเดอร์ lab11
mkdir lab11
cd lab11

# สร้างโครงการ React พร้อม Vite
npm create vite@latest my-react-app -- --template react

# เข้าโฟลเดอร์
cd my-react-app

# ติดตั้ง dependencies
npm install

# เริ่มต้นเซิร์ฟเวอร์
npm run dev
```

เปิด http://localhost:5173 ในเบราว์เซอร์ 👍

### ขั้นตอน 1.2: เข้าใจโครงสร้างโปรเจค

```
my-react-app/
├── src/
│   ├── App.jsx           ← ไฟล์หลัก (แก้ไขที่นี่)
│   ├── main.jsx          ← จุดเริ่มต้น (ไม่ต้องแก้)
│   ├── style.css         ← CSS ทั่วไป
│   └── App.css           ← CSS สำหรับ App
├── public/
├── index.html            ← ไฟล์ HTML เหลือ
└── package.json
```

### ขั้นตอน 1.3: สร้างไฟล์ .gitignore

สร้างไฟล์ `.gitignore` ในรูทของโปรเจค (`my-react-app/`) เพื่อไม่ให้ push ไฟล์ที่ไม่จำเป็น:

```bash
# สร้างไฟล์ .gitignore (Windows)
type nul > .gitignore

# หรือ (Mac/Linux)
touch .gitignore
```

จากนั้น เปิด `.gitignore` ด้วยตัวแก้ไข (VS Code) แล้วเพิ่มเนื้อหา:

```
# Dependencies
node_modules/
npm-debug.log
yarn-debug.log
yarn-error.log
pnpm-debug.log

# Production
dist/
build/

# Environment
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

# Vite
.vite/

# History
.history/
```

บันทึกไฟล์ 👍

### ขั้นตอน 1.4: เริ่มต้นจาก App.jsx

ลบโค้ดเก่า แล้วแทนที่ด้วย:

```javascript
// src/App.jsx

export default function App() {
  return (
    <div>
      <h1>🎓 Lab 11 - React Basics</h1>
      <p>ยินดีต้อนรับสู่เว็บของเรา</p>
    </div>
  );
}
```

บันทึกแล้วดูเบราว์เซอร์ - ควรเห็นข้อความเปลี่ยน 👌

---

## 📋 ส่วนที่ 2: Function Components

### ขั้นตอน 2.1: สร้าง Component แรกของคุณ

แก้ไข `src/App.jsx` เพิ่ม Component ใหม่:

```javascript
// src/App.jsx

// Component 1: Header
function Header() {
  return (
    <header
      style={{ backgroundColor: "#0066cc", color: "white", padding: "20px" }}
    >
      <h1>🎓 ระบบการศึกษา</h1>
    </header>
  );
}

// Component 2: MainContent
function MainContent() {
  return (
    <main style={{ padding: "20px" }}>
      <h2>ยินดีต้อนรับ</h2>
      <p>นี่คือแอปพลิเคชัน React แรกของเรา</p>
    </main>
  );
}

// Component 3: Footer
const Footer = () => {
  return (
    <footer
      style={{
        backgroundColor: "#333",
        color: "white",
        padding: "10px",
        textAlign: "center",
      }}
    >
      <p>© 2024 All Rights Reserved</p>
    </footer>
  );
};

// Component หลัก
export default function App() {
  return (
    <div>
      <Header />
      <MainContent />
      <Footer />
    </div>
  );
}
```

**ตรวจสอบ:** เบราว์เซอร์ต้องแสดง Header, MainContent, Footer ที่เรียง

---

## 📋 ส่วนที่ 3: Props - ส่งข้อมูลระหว่าง Components

### ขั้นตอน 3.1: สร้าง Greeting Component

เพิ่มในไฟล์ `src/App.jsx`:

```javascript
// Greeting Component - รับ Props
function Greeting({ name, age }) {
  return (
    <div
      style={{ padding: "10px", margin: "10px 0", border: "1px solid #ddd" }}
    >
      <h3>สวัสดี {name}! 👋</h3>
      <p>อายุ: {age} ปี</p>
    </div>
  );
}
```

แล้วใช้ใน App:

```javascript
export default function App() {
  return (
    <div>
      <Header />
      <MainContent />

      {/* ใช้ Greeting Component 3 ครั้ง */}
      <section style={{ padding: "20px" }}>
        <h2>👥 ข้อมูลผู้ใช้</h2>
        <Greeting name="สมชาย" age={25} />
        <Greeting name="สมหญิง" age={23} />
        <Greeting name="วิชัย" age={24} />
      </section>

      <Footer />
    </div>
  );
}
```

**ตรวจสอบ:** ต้องแสดง 3 greeting cards ที่มีชื่อและอายุต่างกัน

### ขั้นตอน 3.2: สร้าง ProductCard Component

เพิ่มเติม:

```javascript
// ProductCard Component
function ProductCard({ productName, price, inStock }) {
  return (
    <div
      style={{
        border: "1px solid #ddd",
        padding: "15px",
        margin: "10px",
        borderRadius: "8px",
        backgroundColor: "#f9f9f9",
        width: "200px",
      }}
    >
      <h3>📦 {productName}</h3>
      <p style={{ fontSize: "20px", color: "#e74c3c" }}>฿ {price}</p>
      <p>สถานะ: {inStock ? "มีสินค้า" : "หมด"}</p>
      <button
        style={{
          padding: "10px 20px",
          backgroundColor: "#0066cc",
          color: "white",
          border: "none",
          borderRadius: "4px",
          cursor: "pointer",
        }}
      >
        ซื้อเลย
      </button>
    </div>
  );
}
```

แล้วใช้ใน App:

```javascript
export default function App() {
  return (
    <div>
      <Header />
      <MainContent />

      <section style={{ padding: "20px" }}>
        <h2>👥 ข้อมูลผู้ใช้</h2>
        <Greeting name="สมชาย" age={25} />
        <Greeting name="สมหญิง" age={23} />
        <Greeting name="วิชัย" age={24} />
      </section>

      {/* สินค้า */}
      <section style={{ padding: "20px" }}>
        <h2>🛍️ สินค้า</h2>
        <div style={{ display: "flex", flexWrap: "wrap" }}>
          <ProductCard productName="Laptop" price="35000" inStock={true} />
          <ProductCard productName="Mouse" price="500" inStock={true} />
          <ProductCard productName="Monitor" price="8000" inStock={false} />
        </div>
      </section>

      <Footer />
    </div>
  );
}
```

**ตรวจสอบ:** ต้องแสดง 3 Product Cards ที่มีข้อมูลต่างกัน และมีปุ่ม "ซื้อเลย"

---

## 📋 ส่วนที่ 4: Rendering Lists with .map()

### ขั้นตอน 4.1: สร้าง Component สำหรับแสดงรายการ

```javascript
// StudentCard Component
function StudentCard({ id, name, grade, score }) {
  return (
    <tr>
      <td
        style={{
          padding: "10px",
          border: "1px solid #ddd",
          textAlign: "center",
        }}
      >
        {id}
      </td>
      <td style={{ padding: "10px", border: "1px solid #ddd" }}>{name}</td>
      <td
        style={{
          padding: "10px",
          border: "1px solid #ddd",
          textAlign: "center",
        }}
      >
        {score}
      </td>
      <td
        style={{
          padding: "10px",
          border: "1px solid #ddd",
          textAlign: "center",
        }}
      >
        {grade}
      </td>
    </tr>
  );
}
```

### ขั้นตอน 4.2: ใช้ .map() เพื่อแสดงรายการ

แก้ไข App.jsx:

```javascript
export default function App() {
  // ข้อมูลนิสิต
  const students = [
    { id: 1, name: "สมชาย", score: 95, grade: "A" },
    { id: 2, name: "สมหญิง", score: 88, grade: "B+" },
    { id: 3, name: "วิชัย", score: 92, grade: "A" },
    { id: 4, name: "นิดา", score: 75, grade: "C+" },
    { id: 5, name: "อรุณ", score: 85, grade: "B" },
  ];

  return (
    <div>
      <Header />
      <MainContent />

      <section style={{ padding: "20px" }}>
        <h2>👥 ข้อมูลผู้ใช้</h2>
        <Greeting name="สมชาย" age={25} />
        <Greeting name="สมหญิง" age={23} />
        <Greeting name="วิชัย" age={24} />
      </section>

      <section style={{ padding: "20px" }}>
        <h2>🛍️ สินค้า</h2>
        <div style={{ display: "flex", flexWrap: "wrap" }}>
          <ProductCard productName="Laptop" price="35000" inStock={true} />
          <ProductCard productName="Mouse" price="500" inStock={true} />
          <ProductCard productName="Monitor" price="8000" inStock={false} />
        </div>
      </section>

      {/* รายชื่อนิสิต */}
      <section style={{ padding: "20px" }}>
        <h2>📋 รายชื่อนิสิต</h2>
        <table style={{ borderCollapse: "collapse", width: "100%" }}>
          <thead>
            <tr style={{ backgroundColor: "#0066cc", color: "white" }}>
              <th style={{ padding: "10px", border: "1px solid #ddd" }}>
                ลำดับ
              </th>
              <th style={{ padding: "10px", border: "1px solid #ddd" }}>
                ชื่อ
              </th>
              <th style={{ padding: "10px", border: "1px solid #ddd" }}>
                คะแนน
              </th>
              <th style={{ padding: "10px", border: "1px solid #ddd" }}>
                เกรด
              </th>
            </tr>
          </thead>
          <tbody>
            {students.map((student) => (
              <StudentCard
                key={student.id}
                id={student.id}
                name={student.name}
                score={student.score}
                grade={student.grade}
              />
            ))}
          </tbody>
        </table>
      </section>

      <Footer />
    </div>
  );
}
```

**ตรวจสอบ:** ต้องแสดงตารางกับข้อมูลนิสิต 5 คน

### ขั้นตอน 4.3: สร้าง FruitList Component

เพิ่มเติม:

```javascript
// FruitList Component
function FruitList() {
  const fruits = ["🍎 แอปเปิล", "🍌 กล้วย", "🍊 ส้ม", "🍉 แตงโม", "🥝 กีวี"];

  return (
    <section style={{ padding: "20px" }}>
      <h2>🍎 ผลไม้ยอดนิยม</h2>
      <ul>
        {fruits.map((fruit, index) => (
          <li
            key={index}
            style={{ padding: "8px", margin: "5px 0", fontSize: "18px" }}
          >
            {fruit}
          </li>
        ))}
      </ul>
    </section>
  );
}
```

เพิ่มใน App:

```javascript
export default function App() {
  // ... โค้ดเก่า ...

  return (
    <div>
      <Header />
      <MainContent />
      {/* ... */}
      <FruitList />
      <Footer />
    </div>
  );
}
```

---

## 📋 ส่วนที่ 5: Challenge

### Challenge 1: สร้าง CourseCard Component

สร้าง Component สำหรับแสดงรายวิชา:

```javascript
function CourseCard({ code, name, credits, teacher }) {
  return (
    <div
      style={{
        border: "2px solid #0066cc",
        padding: "20px",
        margin: "10px",
        borderRadius: "8px",
        backgroundColor: "#f0f8ff",
        width: "250px",
      }}
    >
      <h3>📚 {name}</h3>
      <p>
        <strong>รหัส:</strong> {code}
      </p>
      <p>
        <strong>หน่วยกิต:</strong> {credits}
      </p>
      <p>
        <strong>อาจารย์:</strong> {teacher}
      </p>
    </div>
  );
}
```

เพิ่มลงใน App:

```javascript
export default function App() {
  const courses = [
    { code: "001", name: "React Basics", credits: 3, teacher: "อ.สมชาย" },
    { code: "002", name: "JavaScript", credits: 3, teacher: "อ.สมหญิง" },
    { code: "003", name: "CSS Mastery", credits: 2, teacher: "อ.วิชัย" },
  ];

  return (
    <div>
      {/* ... โค้ดเก่า ... */}

      <section style={{ padding: "20px" }}>
        <h2>📚 รายวิชา</h2>
        <div style={{ display: "flex", flexWrap: "wrap" }}>
          {courses.map((course) => (
            <CourseCard
              key={course.code}
              code={course.code}
              name={course.name}
              credits={course.credits}
              teacher={course.teacher}
            />
          ))}
        </div>
      </section>

      {/* ... */}
    </div>
  );
}
```

### Challenge 2: สร้าง Comment Section

```javascript
function CommentCard({ author, message, date }) {
  return (
    <div
      style={{
        border: "1px solid #ddd",
        padding: "15px",
        margin: "10px 0",
        borderRadius: "4px",
        backgroundColor: "#f9f9f9",
      }}
    >
      <strong>{author}</strong>{" "}
      <span style={{ color: "#999", fontSize: "12px" }}>({date})</span>
      <p>{message}</p>
    </div>
  );
}
```

เพิ่มลงใน App:

```javascript
export default function App() {
  const comments = [
    {
      id: 1,
      author: "สมชาย",
      message: "React ยอดเยี่ยมมาก! 🚀",
      date: "2 ชั่วโมงที่แล้ว",
    },
    {
      id: 2,
      author: "สมหญิง",
      message: "เข้าใจง่าย ช่วยด้วย",
      date: "1 ชั่วโมงที่แล้ว",
    },
    {
      id: 3,
      author: "วิชัย",
      message: "Props ยังต้องอธิบายเพิ่มเติมหน่อย",
      date: "30 นาทีที่แล้ว",
    },
  ];

  return (
    <div>
      {/* ... โค้ดเก่า ... */}

      <section style={{ padding: "20px", maxWidth: "600px", margin: "0 auto" }}>
        <h2>💬 ความเห็น</h2>
        {comments.map((comment) => (
          <CommentCard
            key={comment.id}
            author={comment.author}
            message={comment.message}
            date={comment.date}
          />
        ))}
      </section>

      {/* ... */}
    </div>
  );
}
```

---

## Checklist - ตรวจสอบความสำเร็จ

- [ ] สร้างโครงการ React ด้วย Vite ได้
- [ ] เข้าใจ JSX syntax
- [ ] สร้าง Function Components ที่ซ้ำใช้ได้ (Header, Greeting, ProductCard)
- [ ] ส่งข้อมูลผ่าน Props ได้
- [ ] ใช้ .map() เพื่อแสดงรายการ (students, fruits)
- [ ] สร้างอย่างน้อย 2 Components เพิ่มเติม (CourseCard, CommentCard)
- [ ] เบราว์เซอร์แสดงผลถูกต้องโดยไม่มี error

---

## 🧪 การทดสอบ (Testing)

### ทดสอบ 1: ตรวจสอบ Console

เปิด DevTools (F12) ตรวจสอบ Console หาข้อผิดพลาด (Error)

### ทดสอบ 2: เปลี่ยนข้อมูล

ลองแก้ไขข้อมูล students หรือ courses ดูว่าเบราว์เซอร์อัปเดตอัตโนมัติหรือไม่

### ทดสอบ 3: เพิ่มข้อมูล

ลองเพิ่มสินค้าหรือนิสิตรายใหม่ตรวจสอบว่า .map() ทำงานถูกต้อง

---

## 📝 ส่วนเพิ่มเติม

### JSX Rules ที่สำคัญ

```javascript
// ถูก - ใช้ className แทน class
<div className="container">...</div>

// ผิด
<div class="container">...</div>

// ถูก - ปิด tag ทั้งหมด
<img src="logo.png" />
<br />

// ผิด
<img src="logo.png">
<br>

// ถูก - ฝังข้อมูลด้วย {}
<p>จำนวน: {5 + 3}</p>

// ผิด
<p>จำนวน: 5 + 3</p>
```

### Props Destructuring

```javascript
// วิธีเก่า
function Card(props) {
  return <h3>{props.title}</h3>;
}

// วิธีใหม่ (แนะนำ)
function Card({ title, description }) {
  return (
    <>
      <h3>{title}</h3>
      <p>{description}</p>
    </>
  );
}
```

### Naming Convention - ตั้งชื่อให้ถูกต้อง

**Components** ต้องเริ่มด้วยตัวพิมพ์ใหญ่ (PascalCase):

```javascript
// ถูก - Components ใหญ่หมด
function Header() {}
function UserCard() {}
function ProductList() {}

// ผิด - Components เล็ก (React จะไม่รู้จัก)
function header() {}
function userCard() {}
function productList() {}
```

**Variables & Functions** ใช้ camelCase:

```javascript
// ถูก
const userName = "สมชาย";
const productPrice = 5000;
const handleClick = () => {};
const isAvailable = true;

// ผิด
const user_name = "สมชาย";
const product_price = 5000;
const handle_click = () => {};
const is_available = true;
```

**Constants** ใช้ UPPER_SNAKE_CASE:

```javascript
// ถูก - ค่าคงที่
const MAX_ITEMS = 100;
const API_URL = "https://api.example.com";
const DEFAULT_TIMEOUT = 5000;
```

**File Names** - ตามชื่อ Component (PascalCase):

```
src/components/
├── UserProfile.jsx
├── ProductCard.jsx
├── Header.jsx
└── userProfile.jsx
```

**Props Names** - ใช้ camelCase:

```javascript
// ถูก
<Card title="..." description="..." />
<UserCard userName="..." userId={1} />

// ผิด
<Card Title="..." Description="..." />
<UserCard UserName="..." UserId={1} />
```

### Key ใน .map()

```javascript
// ดี - ใช้ unique ID
{
  items.map((item) => <div key={item.id}>{item.name}</div>);
}

// ⚠️ ไม่แนะนำ - ใช้ index เป็น key
{
  items.map((item, index) => <div key={index}>{item.name}</div>);
}
```

---

## 📝 คำถามท้ายปฏิบัติการ - วัดความเข้าใจ

### ส่วนที่ 1: JSX Syntax & JSX Rules

**คำถาม 1.1:** จงอธิบายความแตกต่างระหว่าง `class` และ `className` ใน JSX พร้อมทำให้ตัวอย่างที่แสดงเหตุผลว่าทำไม React ต้องการใช้ `className`

**แนวทางการตอบคำถาม:**
อธิบายให้ชัดเจน มีตัวอย่างถูกต้อง และอธิบายเหตุผล

**ตัวอย่างคำตอบ:**

```
JSX ต้องใช้ className แทน class เพราะ:
1. class เป็นคำสงวน (reserved keyword) ใน JavaScript
2. JSX แปลง HTML attribute ให้เป็น JavaScript properties
3. ตัวอย่าง:
   - ถูก: <div className="container">...</div>
   - ผิด: <div class="container">...</div> (error)

ใน JavaScript ทั่วไป, className ใช้เพื่อหลีกเลี่ยงการชนกับคำสงวน class
```

---

**คำถาม 1.2:** จงเขียน Component ที่ใช้ JSX rules ให้ถูกต้องตามตัวอย่าง

```javascript
// ต้องเขียนให้ถูกต้อง (แก้ไขโค้ดที่ผิด)
function ProfileCard() {
  const userName = "สมชาย";
  const age = 25;

  return (
    <div class="card">
      <h3>ชื่อ: userName</h3>
      <p>อายุ: age</p>
      <img src="avatar.png">
      <button>คลิกที่นี่</button>
    </div>
  );
}
```

ให้แสดง Component ที่แก้ไขแล้ว และอธิบายข้อผิดพลาดแต่ละข้อ

---

### ส่วนที่ 2: Function Components

**คำถาม 2.1:** จงอธิบายความสำคัญของการตั้งชื่อ Component ด้วยตัวพิมพ์ใหญ่ (PascalCase) และแสดงตัวอย่างอย่างน้อย 2 ตัวอย่าง

---

**คำถาม 2.2:** จงเปรียบเทียบวิธีการเขียน Function Component แบบ regular function และ arrow function พร้อมกล่าวถึง ข้อดีข้อเสีย

---

### ส่วนที่ 3: Props

**คำถาม 3.1:** จงสร้าง Component ชื่อ `ProductCard` ที่รับ Props: `name`, `price`, `inStock` พร้อมอธิบายวิธีการส่ง Props จาก Parent Component

```javascript
// ต้องสร้าง Component นี้:
// 1. ProductCard Component
// 2. แสดงวิธีการใช้ใน App.jsx (ส่ง Props)
// 3. อธิบายความแตกต่างระหว่าง string, number, boolean props
```

---

**คำถาม 3.2:** Props destructuring คืออะไร? จงแสดงตัวอย่างเปรียบเทียบระหว่าง:

1. วิธีเก่า: `function Card(props) { ... }`
2. วิธีใหม่: `function Card({ title, description }) { ... }`

และอธิบายว่าทำไมวิธีใหม่ (destructuring) จึงเป็น best practice

---

### ส่วนที่ 4: Lists & .map()

**คำถาม 4.1:** จงอธิบายว่า `.map()` ทำงานอย่างไรในการแสดงรายการข้อมูล พร้อมตัวอย่างโค้ดที่แสดง:

1. การใช้ .map() เพื่อแสดง list ของ Component
2. เหตุผลว่าทำไมต้องใช้ `key` property
3. ข้อแตกต่างระหว่าง key={index} และ key={item.id}

---

**คำถาม 4.2:** สร้าง Component ที่ใช้ .map() เพื่อแสดง:

1. รายชื่อนิสิต (array of objects ที่มี id, name, grade)
2. แสดงเป็นตาราง โดยใช้ .map() ในการสร้าง <tr> แต่ละแถว
3. อธิบายเหตุผลว่าทำไมต้องใช้ unique ID เป็น key

---

### ส่วนที่ 5: Best Practices & Naming Conventions

**คำถาม 5.1:** จงอธิบายและยกตัวอย่างการตั้งชื่อในแต่ละประเภท ทั้งแบบที่ถูก และแบบที่ผิด:

1. **Component Names** - ตั้งชื่อแบบไหน?
2. **Variable Names** - ตั้งชื่อแบบไหน?
3. **Constants** - ตั้งชื่อแบบไหน?
4. **File Names** - ตั้งชื่อแบบไหน?

---

**คำถาม 5.2:** จากโค้ด Component ต่อไปนี้ให้บอก:

1. ส่วนที่ตั้งชื่อถูกต้อง
2. ส่วนที่ตั้งชื่อผิด (ถ้ามี)
3. แก้ไขโค้ดให้เป็น best practice

```javascript
function user_profile({ user_name, user_age, IS_PREMIUM }) {
  const user_data = {
    name: user_name,
    age: user_age,
    isPremium: IS_PREMIUM,
  };

  return (
    <div>
      <h3>{user_data.name}</h3>
      <p>{user_data.age} ปี</p>
    </div>
  );
}
```

---

## 📚 ทรัพยากรเพิ่มเติม

- [MDN: React (JSX)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
- [React Official Docs: Components](https://react.dev/learn/describing-the-ui)
- [Vite Documentation](https://vitejs.dev/)

---

## 🎓 ขั้นตอนถัดไป

ในสัปดาห์ถัดไป เราจะเรียนรู้:

- useState Hook - จัดการ State
- Event Handling - ตอบสนองต่อการกดปุ่ม/เหตุการณ์
- Controlled Components - ฟอร์มที่ติดต่อได้

---
