# สัปดาห์ที่ 11: React โครงสร้างพื้นฐานและ Components

## สารบัญ

1. [React และการตั้งค่า Vite](#react-และการตั้งค่า-vite)
   - [React ความหมายและแนวคิด](#react-ความหมายและแนวคิด)
   - [เหตุผลในการใช้ Vite](#เหตุผลในการใช้-vite)
   - [ขั้นตอนติดตั้ง Vite และ React](#ขั้นตอนติดตั้ง-vite-และ-react)
   - [โครงสร้างพื้นฐานของโครงการ](#โครงสร้างพื้นฐานของโครงการ)

2. [ไวยากรณ์ JSX](#ไวยากรณ์-jsx)
   - [นิยามของ JSX](#นิยามของ-jsx)
   - [ตัวอย่างพื้นฐาน](#ตัวอย่างพื้นฐาน)
   - [กฎเกณฑ์สำคัญในการใช้ JSX](#กฎเกณฑ์สำคัญในการใช้-jsx)
   - [ตัวอย่างการนำไปใช้งาน](#ตัวอย่างการนำไปใช้งาน)

3. [Function Components](#function-components)
   - [นิยามและความหมายของ Component](#นิยามและความหมายของ-component)
   - [โครงสร้างพื้นฐาน](#โครงสร้างพื้นฐาน)
   - [ข้อปฏิบัติ](#ข้อปฏิบัติ)
   - [ตัวอย่างการสร้าง Component](#ตัวอย่างการสร้าง-component)

4. [Props ส่งข้อมูลระหว่าง Component](#props-ส่งข้อมูลระหว่าง-component)
   - [นิยามของ Props](#นิยามของ-props)
   - [ตัวอย่างพื้นฐาน](#ตัวอย่างพื้นฐาน-1)
   - [ตัวอย่างที่ 1: Product Card](#ตัวอย่างที่-1-product-card)
   - [ตัวอย่างที่ 2: User Card](#ตัวอย่างที่-2-user-card)
   - [ข้อปฏิบัติเกี่ยวกับ Key](#ข้อปฏิบัติเกี่ยวกับ-key)

5. [การแสดงผลรายการข้อมูล](#การแสดงผลรายการข้อมูล)
   - [แนวคิดการใช้ map()](#แนวคิดการใช้-map)
   - [ตัวอย่างพื้นฐาน](#ตัวอย่างพื้นฐาน-2)
   - [ตัวอย่างที่ 1: รายชื่องักศึกษา](#ตัวอย่างที่-1-รายชื่อนักศึกษา)
   - [ตัวอย่างที่ 2: รายการ Card](#ตัวอย่างที่-2-รายการ-card)

6. [Lab 11: สร้าง Components ที่นำกลับใช้ได้](#lab-11-สร้าง-components-ที่นำกลับใช้ได้)

7. [สรุปเนื้อหา](#สรุปเนื้อหา)

---

## มูลเหตุและวัตถุประสงค์ของสัปดาห์นี้

เนื้อหาที่จะศึกษาในสัปดาห์นี้ ได้แก่:

- React โครงสร้างพื้นฐาน
- ไวยากรณ์ JSX และการนำไปใช้
- Function Components
- Props และการส่งข้อมูล
- การแสดงผลรายการข้อมูลด้วย map()

---

## React และการตั้งค่า Vite

### React ความหมายและแนวคิด

**React** เป็นไลบรารี JavaScript ที่ใช้สำหรับสร้างส่วนติดต่อผู้ใช้ (User Interface) ที่มีคุณสมบัติในการโต้ตอบ โดยการแบ่งส่วนติดต่อออกเป็นส่วนย่อยที่เรียกว่า Components ซึ่งสามารถนำไปครอบครองใช้ได้

### เหตุผลในการใช้ Vite

**Vite** เป็นเครื่องมือ Build ที่ออกแบบมาเพื่อให้ React ทำงานได้เร็วขึ้น และให้สะดวกต่อการพัฒนา

### ขั้นตอนติดตั้ง Vite และ React

```bash
# 1. สร้างโครงการใหม่
npm create vite@latest my-react-app -- --template react

# 2. เข้าไปในโฟลเดอร์
cd my-react-app

# 3. ติดตั้ง dependencies
npm install

# 4. เริ่มต้นการพัฒนา
npm run dev
```

**ผลลัพธ์:**

```
Local:   http://localhost:5173/
```

เปิด URL นี้ในเบราว์เซอร์

### โครงสร้างพื้นฐานของโครงการ

```
my-react-app/
├── node_modules/          (ไลบรารีที่ติดตั้ง)
├── public/                 (ไฟล์สาธารณะ)
├── src/                    (โค้ด React ของเรา)
│   ├── App.jsx            (Component หลัก)
│   ├── main.jsx           (จุดเริ่มต้น)
│   └── style.css          (CSS)
├── package.json
├── vite.config.js
└── index.html
```

---

## ไวยากรณ์ JSX

### นิยามของ JSX

**JSX** เป็นวิธีการเขียน HTML ข้างในโค้ด JavaScript ซึ่ง React จะแปลงให้เป็น JavaScript ทั่วไป

### ตัวอย่างพื้นฐาน

```javascript
// JSX (เขียนในรูป HTML)
const message = <h1>สวัสดี React!</h1>;

// React แปลงเป็น:
const message = React.createElement("h1", null, "สวัสดี React!");
```

### กฎเกณฑ์สำคัญในการใช้ JSX

#### 1. ใช้ JSX ในการส่งคืนค่าของ Component

```javascript
export default function Welcome() {
  return <h1>ยินดีต้อนรับ</h1>;
}
```

#### 2. ใช้ className แทน class

```javascript
// ถูก
<div className="container">เนื้อหา</div>

// ไม่ถูก: class จะไม่ทำงาน
<div class="container">เนื้อหา</div>
```

#### 3. ใช้เครื่องหมายปีกกาสำหรับการใส่โค้ด JavaScript

```javascript
// ถูก
<p>จำนวน: {5 + 3}</p>           // แสดง: จำนวน: 8
<p>ชื่อ: {name}</p>              // แสดง: ชื่อ: สมชาย

// ไม่ถูก
<p>จำนวน: 5 + 3</p>              // แสดง: จำนวน: 5 + 3
```

#### 4. ปิด tag ทั้งหมด

```javascript
// ถูก
<img src="logo.png" />
<br />
<input type="text" />

// ไม่ถูก
<img src="logo.png">
<br>
<input type="text">
```

#### 5. ใช้ camelCase สำหรับคุณสมบัติ

```javascript
// ถูก
<input onChange={handleChange} />

// ไม่ถูก
<input onchange={handleChange} />
```

### ตัวอย่างการนำไปใช้งาน

```javascript
export default function Introduction() {
  const studentName = "สมชาย";
  const score = 95;

  return (
    <div className="intro">
      <h1>ยินดีต้อนรับ {studentName}</h1>
      <p>คะแนน: {score}/100</p>
      <p>ผลลัพธ์: {score >= 80 ? "ผ่าน" : "ไม่ผ่าน"}</p>
    </div>
  );
}
```

---

## Function Components

### นิยามและความหมายของ Component

**Component** เป็นฟังก์ชัน JavaScript ที่ส่งคืนค่า JSX เพื่อแสดงผลบนหน้าเว็บ

### โครงสร้างพื้นฐาน

```javascript
// 1. ประกาศ Component โดยให้ชื่อเริ่มต้นด้วยตัวพิมพ์ใหญ่
function Greeting() {
  return <h1>สวัสดี</h1>
}

// 2. ส่งออก Component
export default Greeting

// หรือเป็นบรรทัดเดียว
export default function Greeting() {
  return <h1>สวัสดี</h1>
}
```

### ข้อปฏิบัติ

```javascript
// ไม่ถูก: ชื่อต้องเริ่มด้วยตัวพิมพ์ใหญ่
const greeting = () => <h1>สวัสดี</h1>;

// ถูก
const Greeting = () => <h1>สวัสดี</h1>;
```

### ตัวอย่างการสร้าง Component

```javascript
// Component 1: ฟังก์ชันปกติ
function Header() {
  return (
    <header>
      <h1>ระบบการศึกษา</h1>
      <p>ยินดีต้อนรับเข้าสู่เว็บไซต์ของเรา</p>
    </header>
  );
}

// Component 2: Arrow function
const Footer = () => {
  return (
    <footer>
      <p>ลิขสิทธิ 2024 สงวนสิทธิ์ทั้งหมด</p>
    </footer>
  );
};

// Component 3: ใช้ใน App
export default function App() {
  return (
    <div>
      <Header />
      <main>
        <p>เนื้อหาหลัก</p>
      </main>
      <Footer />
    </div>
  );
}
```

---

## Props ส่งข้อมูลระหว่าง Component

### นิยามของ Props

**Props** (Properties) เป็นข้อมูลที่ส่งจาก Parent Component ไปยัง Child Component ซึ่งช่วยให้ Component สามารถนำไปครอบครองใช้ได้

### ตัวอย่างพื้นฐาน

```javascript
// 1. Parent Component (ส่ง Props)
export default function App() {
  return <Card title="React" description="ไลบรารี UI" />;
}

// 2. Child Component (รับ Props)
function Card(props) {
  return (
    <div>
      <h2>{props.title}</h2>
      <p>{props.description}</p>
    </div>
  );
}
```

### ตัวอย่างที่ 1: Product Card

```javascript
// Component
function ProductCard(props) {
  return (
    <div style={{ border: "1px solid #ddd", padding: "20px" }}>
      <h3>{props.name}</h3>
      <p>ราคา: {props.price} บาท</p>
      <p>คงเหลือ: {props.stock} ชิ้น</p>
      <button>ซื้อเลย</button>
    </div>
  );
}

// ใช้ Component
export default function App() {
  return (
    <div>
      <ProductCard name="iPhone" price="30000" stock="5" />
      <ProductCard name="Samsung" price="25000" stock="10" />
      <ProductCard name="Oppo" price="15000" stock="0" />
    </div>
  );
}
```

### ตัวอย่างที่ 2: User Card

```javascript
function UserCard({ name, email, role }) {
  return (
    <div
      style={{
        border: "1px solid #ccc",
        borderRadius: "8px",
        padding: "20px",
        margin: "10px",
      }}
    >
      <h3>{name}</h3>
      <p>อีเมล: {email}</p>
      <p>ตำแหน่ง: {role}</p>
    </div>
  );
}

export default function App() {
  return (
    <div>
      <UserCard name="สมชาย" email="somchai@example.com" role="นักศึกษา" />
      <UserCard name="สมหญิง" email="somying@example.com" role="อาจารย์" />
    </div>
  );
}
```

### การใช้ Destructuring Props (วิธีที่แนะนำ)

```javascript
// วิธีเก่า
function greeting(props) {
  return <h1>สวัสดี {props.name}</h1>;
}

// วิธีใหม่ - Destructuring (ที่แนะนำ)
function Greeting({ name, age }) {
  return (
    <div>
      <h1>สวัสดี {name}</h1>
      <p>อายุ: {age}</p>
    </div>
  );
}

export default function App() {
  return <Greeting name="สมชาย" age={25} />;
}
```

---

## การแสดงผลรายการข้อมูล

### แนวคิดการใช้ map()

เมื่อมีข้อมูลหลายรายการ สามารถใช้ `.map()` เพื่อสร้าง Component ซ้ำ ๆ ได้

### ตัวอย่างพื้นฐาน

```javascript
export default function App() {
  // ข้อมูลรายการ
  const fruits = ["แอปเปิล", "กล้วย", "สม้อ", "มะม่วง"];

  return (
    <div>
      <h1>ผลไม้</h1>
      <ul>
        {fruits.map((fruit, index) => (
          <li key={index}>{fruit}</li>
        ))}
      </ul>
    </div>
  );
}
```

**ผลลัพธ์:**

```
ผลไม้
• แอปเปิล
• กล้วย
• สม้อ
• มะม่วง
```

### ตัวอย่างที่ 1: รายชื่อนักศึกษา

```javascript
export default function StudentList() {
  const students = [
    { id: 1, name: "สมชาย", grade: "A" },
    { id: 2, name: "สมหญิง", grade: "B" },
    { id: 3, name: "วิชัย", grade: "A" },
  ];

  return (
    <div>
      <h2>รายชื่อนักศึกษา</h2>
      <table border="1" cellPadding="10">
        <thead>
          <tr>
            <th>ลำดับที่</th>
            <th>ชื่อ</th>
            <th>เกรด</th>
          </tr>
        </thead>
        <tbody>
          {students.map((student) => (
            <tr key={student.id}>
              <td>{student.id}</td>
              <td>{student.name}</td>
              <td>{student.grade}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}
```

### ตัวอย่างที่ 2: รายการ Card

```javascript
function ProductCard({ id, title, price }) {
  return (
    <div
      style={{
        border: "1px solid #ddd",
        padding: "15px",
        margin: "10px",
        borderRadius: "8px",
        backgroundColor: "#f9f9f9",
      }}
    >
      <h3>{title}</h3>
      <p style={{ color: "#e74c3c", fontSize: "18px" }}>บาท {price}</p>
      <button>ซื้อ</button>
    </div>
  );
}

export default function App() {
  const products = [
    { id: 1, title: "Laptop", price: 35000 },
    { id: 2, title: "Mouse", price: 500 },
    { id: 3, title: "Monitor", price: 8000 },
  ];

  return (
    <div>
      <h1>สินค้าเพื่อขาย</h1>
      <div style={{ display: "flex", flexWrap: "wrap" }}>
        {products.map((product) => (
          <ProductCard
            key={product.id}
            id={product.id}
            title={product.title}
            price={product.price}
          />
        ))}
      </div>
    </div>
  );
}
```

### ข้อปฏิบัติเกี่ยวกับ Key

```javascript
// ไม่ควรใช้: ใช้ index เป็น key (อาจเกิดปัญหา)
{
  items.map((item, index) => <div key={index}>{item}</div>);
}

// ควรใช้: ใช้ unique ID (ดีกว่า)
{
  items.map((item) => <div key={item.id}>{item.name}</div>);
}
```

---

## Lab 11: สร้าง Components ที่นำกลับใช้ได้

### ภารกิจ

สร้างไฟล์ต่อไปนี้ในโฟลเดอร์ `src/components/`:

1. **Card.jsx** - Component แสดงข้อมูล
2. **List.jsx** - Component แสดงรายการ
3. **UserProfile.jsx** - Component แสดงข้อมูลผู้ใช้

### ขั้นตอนการปฏิบัติ

#### ขั้นตอน 1: สร้าง Card.jsx

```javascript
// src/components/Card.jsx
export default function Card({ title, description, image }) {
  return (
    <div
      style={{
        border: "1px solid #ddd",
        borderRadius: "8px",
        padding: "20px",
        backgroundColor: "#fff",
        boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
      }}
    >
      {image && <img src={image} alt={title} width="100%" />}
      <h3>{title}</h3>
      <p>{description}</p>
    </div>
  );
}
```

#### ขั้นตอน 2: สร้าง List.jsx

```javascript
// src/components/List.jsx
export default function List({ items, title }) {
  return (
    <div>
      <h2>{title}</h2>
      <ul>
        {items.map((item, index) => (
          <li key={index} style={{ padding: "8px", margin: "5px 0" }}>
            {item}
          </li>
        ))}
      </ul>
    </div>
  );
}
```

#### ขั้นตอน 3: สร้าง UserProfile.jsx

```javascript
// src/components/UserProfile.jsx
export default function UserProfile({ name, email, role, image }) {
  return (
    <div
      style={{
        border: "2px solid #007bff",
        borderRadius: "8px",
        padding: "20px",
        textAlign: "center",
        maxWidth: "300px",
        margin: "20px auto",
      }}
    >
      {image && (
        <img
          src={image}
          alt={name}
          style={{
            width: "100px",
            height: "100px",
            borderRadius: "50%",
            marginBottom: "10px",
          }}
        />
      )}
      <h2>{name}</h2>
      <p>
        <strong>Email:</strong> {email}
      </p>
      <p>
        <strong>Role:</strong> {role}
      </p>
    </div>
  );
}
```

#### ขั้นตอน 4: ใช้ใน App.jsx

```javascript
// src/App.jsx
import Card from "./components/Card";
import List from "./components/List";
import UserProfile from "./components/UserProfile";

export default function App() {
  const courses = ["React", "JavaScript", "CSS"];
  const teachers = [
    { name: "สมชาย", email: "somchai@school.com", role: "อาจารย์" },
    { name: "สมหญิง", email: "somying@school.com", role: "อาจารย์" },
  ];

  return (
    <div style={{ padding: "20px" }}>
      <h1>ระบบการศึกษา</h1>

      {/* Card List */}
      <div style={{ display: "flex", gap: "20px", marginBottom: "30px" }}>
        <Card title="React" description="ไลบรารี JavaScript สำหรับสร้าง UI" />
        <Card title="Vue" description="Framework ที่ง่ายต่อการเรียนรู้" />
      </div>

      {/* Course List */}
      <List items={courses} title="วิชาที่เรียน" />

      {/* User Profiles */}
      <div>
        <h2>อาจารย์</h2>
        <div style={{ display: "flex", gap: "20px", flexWrap: "wrap" }}>
          {teachers.map((teacher) => (
            <UserProfile
              key={teacher.email}
              name={teacher.name}
              email={teacher.email}
              role={teacher.role}
            />
          ))}
        </div>
      </div>
    </div>
  );
}
```

### รายการตรวจสอบ

- สร้าง Component 3 ตัวที่นำกลับใช้ได้
- ใช้ Props เพื่อส่งข้อมูล
- ใช้ .map() เพื่อแสดงรายการ
- มีการจัดรูปแบบด้วย inline styles

---

## สรุปเนื้อหา

| หัวข้อ           | สิ่งที่เรียนรู้             |
| ---------------- | --------------------------- |
| **React + Vite** | Setup โครงการใหม่           |
| **JSX**          | เขียน HTML ใน JavaScript    |
| **Components**   | ฟังก์ชัน JS ที่คืนค่า JSX   |
| **Props**        | ส่งข้อมูลระหว่าง Components |
| **Lists**        | ใช้ .map() แสดงรายการ       |

---

## เนื้อหาที่จะศึกษาต่อ

ในสัปดาห์ถัดไป จะศึกษา:

- useState Hook - การจัดการสถานะ (State)
- Event Handling - การตอบสนองต่อเหตุการณ์
- Form Inputs - ฟอร์มติดต่อ
- Conditional Rendering - การแสดงผลตามเงื่อนไข
