# คู่มือเขียน React - ความรู้พื้นฐานที่จำเป็น

## สารบัญ

1. [ความรู้พื้นฐาน](#ความรู้พื้นฐาน)
2. [การติดตั้ง](#การติดตั้ง)
3. [JSX และ Rendering](#jsx-และ-rendering)
4. [Components](#components)
5. [Props](#props)
6. [State (useState)](#state-usestate)
7. [Side Effects (useEffect)](#side-effects-useeffect)
8. [Event Handling](#event-handling)
9. [Conditional Rendering](#conditional-rendering)
10. [Lists & Keys](#lists--keys)
11. [Forms](#forms)
12. [Common Hooks](#common-hooks)
13. [Custom Hooks](#custom-hooks)
14. [Performance Optimization (useCallback & useMemo)](#performance-optimization-usecallback--usememo)
15. [Context API](#context-api)
16. [Best Practices](#best-practices)

---

## ความรู้พื้นฐาน

### React คืออะไร?

React เป็น JavaScript Library สำหรับสร้าง User Interface (UI) โดยใช้ **Component-based** architecture

### ทำไมต้อง React?

- **Reactive** - UI อัปเดตอัตโนมัติเมื่อ state เปลี่ยน
- **Reusable** - สร้าง Component ซ้ำใช้ได้
- **Maintainable** - โค้ดเป็นระเบียบและง่ายต่อการแก้ไข
- **Performance** - Virtual DOM ทำให้เร็ว

---

## การติดตั้ง

### ข้อกำหนดพื้นฐาน

- Node.js v14+ (ดาวน์โหลดได้ที่ https://nodejs.org/)
- npm หรือ yarn (มาพร้อมกับ Node.js)
- Text Editor: VS Code, Sublime, WebStorm ฯลฯ

> **สำหรับผู้เรียน:**
>
> 1. ดาวน์โหลด Node.js เสียก่อน (npm จะมาด้วยอัตโนมัติ)
> 2. ตั้ง Editor เป็น VS Code (แนะนำ ใช้ง่ายที่สุด)

### ตรวจสอบ Node.js และ npm

```bash
node --version    # ควรแสดง v14 ขึ้นไป
npm --version     # ควรแสดง v6 ขึ้นไป
```

### วิธี 1: สร้าง Project ด้วย Vite (แนะนำ - เร็วมาก)

```bash
# สร้าง project ใหม่
npm create vite@latest my-react-app -- --template react

# เข้าโฟลเดอร์
cd my-react-app

# ติดตั้ง dependencies
npm install

# รัน development server
npm run dev
```

> **เลือกวิธีนี้** ถ้าคุณเริ่มต้นใหม่ (เป็นตัวเลือกที่ดีที่สุด)

### วิธี 2: สร้าง Project ด้วย Create React App

```bash
# สร้าง project ใหม่
npx create-react-app my-react-app

# เข้าโฟลเดอร์
cd my-react-app

# รัน development server
npm start
```

> **เลือกวิธีนี้** ถ้าใช้ macOS/Linux และต้องการติดตั้งแบบสม่ำเสมอ (ช้ากว่า Vite)

### วิธี 3: ใช้ React ใน HTML ปกติ

```html
<!DOCTYPE html>
<html>
  <head>
    <script
      crossorigin
      src="https://unpkg.com/react@18/umd/react.production.min.js"
    ></script>
    <script
      crossorigin
      src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
    ></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      function App() {
        return <h1>สวัสดี React!</h1>;
      }

      const root = ReactDOM.createRoot(document.getElementById("root"));
      root.render(<App />);
    </script>
  </body>
</html>
```

> **เลือกวิธีนี้** ถ้า:
>
> - ต้องการทดลองแบบรวดเร็ว (ไม่ต้อง `npm install`)
> - รวม React เข้าในเว็บไซต์เดิม (legacy)
> - ไม่แนะนำสำหรับ production เนื่องจากความเร็วที่ช้า

### โครงสร้าง Project (Vite/Create React App)

```
my-react-app/
├── node_modules/          # Packages ที่ติดตั้ง
├── public/               # Assets ที่ public (รูปภาพ, icon, ฯลฯ)
├── src/
│   ├── App.jsx          # Component หลัก
│   ├── App.css          # Stylesheet สำหรับ App
│   ├── main.jsx         # Entry point
│   └── index.css        # Global stylesheet
├── index.html           # HTML หลัก
├── package.json         # ข้อมูล project และ dependencies
├── package-lock.json    # Lock file สำหรับ npm
└── vite.config.js       # Config สำหรับ Vite (หรือ react-scripts สำหรับ CRA)
```

### Commands ที่ใช้บ่อย

| Command           | ความหมาย                                  |
| ----------------- | ----------------------------------------- |
| `npm install`     | ติดตั้ง packages ทั้งหมด                  |
| `npm run dev`     | รัน development server (Vite)             |
| `npm start`       | รัน development server (Create React App) |
| `npm run build`   | สร้าง production build                    |
| `npm run preview` | ดูตัวอย่าง production build (Vite)        |
| `npm test`        | รัน unit tests                            |

### ติดตั้ง Package เพิ่มเติม

```bash
# ติดตั้ง React Router (สำหรับ routing)
npm install react-router-dom

# ติดตั้ง Axios (สำหรับ API calls)
npm install axios

# ติดตั้ง styling library
npm install styled-components

# ติดตั้ง state management
npm install zustand  # หรือ redux, jotai, ฯลฯ
```

### เรียก React Components ใน src/main.jsx

```javascript
// src/main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);
```

### ตัวอย่าง: หลังติดตั้งเสร็จ

แก้ไข `src/App.jsx`:

```javascript
import { useState } from "react";
import "./App.css";

function App() {
  const [count, setCount] = useState(0);

  return (
    <div className="App">
      <h1>สวัสดี React!</h1>
      <p>ตัวนับ: {count}</p>
      <button onClick={() => setCount(count + 1)}>เพิ่ม</button>
    </div>
  );
}

export default App;
```

จากนั้น browser จะรีเฟรชอัตโนมัติและแสดง app ของคุณ

### Troubleshooting

| ปัญหา                    | วิธีแก้                                    |
| ------------------------ | ------------------------------------------ |
| `command not found: npm` | ติดตั้ง Node.js ใหม่                       |
| Port 5173/3000 ถูกใช้งาน | เปลี่ยน port: `npm run dev -- --port 3001` |
| Module not found         | รัน `npm install` อีกครั้ง                 |
| Components ไม่แสดง       | ตรวจสอบการ import/export ถูกต้อง           |
| Styling ไม่ทำงาน         | ตรวจสอบการ import CSS ถูกต้อง              |

---

## JSX และ Rendering

### JSX คืออะไร?

JSX คือ syntax extension ที่ผสมผสาน HTML กับ JavaScript

```javascript
// JSX - ดูเหมือน HTML แต่อยู่ใน JavaScript
const element = <h1>สวัสดี {name}</h1>;

// แปลเป็น JavaScript
const element = React.createElement("h1", null, `สวัสดี ${name}`);
```

### กฎ JSX ที่สำคัญ

| กฎ                      | ตัวอย่าง                                 |
| ----------------------- | ---------------------------------------- |
| แตกต่างจาก HTML         | `class` → `className`, `for` → `htmlFor` |
| Tag เปิดและปิด          | `<img src="..." />` (self-closing)       |
| ใช้ curly braces {}     | `<p>{variable}</p>`                      |
| ต้องมี root element     | `<div>...</div>` หรือ `<>...</>`         |
| attribute ใช้ camelCase | `onClick`, `onChange`, `backgroundColor` |

```javascript
function App() {
  const title = "React Guide";
  const isReady = true;
  const styles = { color: "blue", fontSize: "20px" };

  return (
    <>
      <h1 className="title">{title}</h1>
      <p style={styles}>{isReady ? "พร้อม!" : "ยังไม่พร้อม"}</p>
      <img src="logo.png" alt="logo" />
    </>
  );
}
```

---

## Components

### Function Component (ใช้ปัจจุบัน)

Component คือ function ที่ return JSX

```javascript
//  ถูกต้อง - PascalCase
function Welcome() {
  return <h1>สวัสดี!</h1>;
}

//  หรือ arrow function
const Welcome = () => {
  return <h1>สวัสดี!</h1>;
};

//  Short syntax (implicit return)
const Welcome = () => <h1>สวัสดี!</h1>;
```

### การ Render Component

```javascript
function App() {
  return (
    <>
      <Welcome /> {/* self-closing */}
      <Welcome></Welcome> {/* or with closing tag */}
    </>
  );
}
```

### กฎการตั้งชื่อ

```javascript
//  ผิด - lowercase
function welcome() { }

//  ถูก - PascalCase
function Welcome() { }

//  ผิด - ใช้ component เหมือน HTML tag
<welcome />

//  ถูก - ใช้ PascalCase
<Welcome />
```

---

## Props

Props = Properties = ข้อมูลที่ส่งจาก parent ไปให้ child component

### เบื้องต้น

```javascript
// กำหนด Component
function Greeting({ name, age }) {
  return (
    <p>
      สวัสดี {name}, อายุ {age} ปี
    </p>
  );
}

// ใช้งาน
<Greeting name="สมชาย" age="25" />;
```

### วิธีรับ Props แบบต่างๆ

```javascript
// 1. แบบ destructuring
function Card({ title, content, color = "blue" }) {
  return (
    <div style={{ color }}>
      {title}: {content}
    </div>
  );
}

// 2. แบบ object
function Card(props) {
  return (
    <div>
      {props.title}: {props.content}
    </div>
  );
}

// 3. Default value
function Button({ text = "Click me", disabled = false }) {
  return <button disabled={disabled}>{text}</button>;
}
```

### การกระจาย Props

```javascript
const config = { name: "John", age: 30, city: "Bangkok" };

// กระจาย object เป็น props
<UserCard {...config} />

// เทียบเท่ากับ
<UserCard name="John" age={30} city="Bangkok" />
```

> **หมายเหตุให้ผู้เรียน:** `...config` คือ spread operator ที่กระจาย object ออกมา
>
> - ใช้เมื่อข้อมูลอยู่ใน object แล้ว ไม่ต้องเขียน props ทีละตัว
> - หมายความว่าการใช้ spread operator (`...`) เพื่อส่งค่าทั้งหมดในครั้งเดียว

### ข้อควรรู้เกี่ยวกับ Props

- **Props เป็น read-only** (ห้ามแก้ไข)
- **ส่งจาก parent ไปยัง child เท่านั้น**
- **Props เปลี่ยน → Component re-render อัตโนมัติ**

> **ทำไมห้ามแก้ props?**
>
> - Props มาจาก parent (คอมโพเนนต์แม่)
> - Child (คอมโพเนนต์ลูก) ต้องปฏิบัติตามที่ parent กำหนด
> - ถ้า child แก้เอง parent ไม่รู้ว่ามีการเปลี่ยนแปลง ส่งผลให้ UI ไม่ทำงานถูกต้อง
> - หากต้องแก้ไขค่า ให้ parent เป็นผู้ตัดสินใจและส่งการเปลี่ยนแปลงลงมา

```javascript
//  ผิด - ห้ามแก้ props
function BadComponent({ name }) {
  name = "new name"; //  ผิด!
}

//  ถูก - ใช้ state ถ้าต้องแก้ไข
function GoodComponent({ name }) {
  const [displayName, setDisplayName] = useState(name);

  const changeName = () => {
    setDisplayName("new name");
  };
}
```

---

## State (useState)

State = ข้อมูลที่เปลี่ยนแปลงได้ภายใน component

### Hook: useState

```javascript
import { useState } from "react";

function Counter() {
  // [state, function ในการแก้ state] = useState(initial value)
  const [count, setCount] = useState(0);

  return (
    <>
      <p>ตัวนับ: {count}</p>
      <button onClick={() => setCount(count + 1)}>เพิ่ม</button>
    </>
  );
}
```

### State ที่ซับซ้อนหรือเป็นอ็อบเจ็กต์

```javascript
function Employee() {
  // State ที่เป็น object
  const [person, setPerson] = useState({
    name: "สมชาย",
    age: 25,
    position: "Developer",
  });

  // อัปเดต property เดียว ต้องใช้ spread operator
  const handleAgeIncrease = () => {
    setPerson({
      ...person,
      age: person.age + 1,
    });
  };

  // หรือใช้ function update
  const handleNameChange = (newName) => {
    setPerson((prev) => ({
      ...prev,
      name: newName,
    }));
  };

  return (
    <>
      <p>
        {person.name} อายุ {person.age}
      </p>
      <button onClick={handleAgeIncrease}>อายุเพิ่ม 1</button>
    </>
  );
}
```

### State ที่เป็นอาร์เรย์

```javascript
function TodoList() {
  const [todos, setTodos] = useState([]);

  // เพิ่ม todo
  const addTodo = (text) => {
    setTodos([...todos, { id: Date.now(), text }]);
  };

  // ลบ todo
  const deleteTodo = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id));
  };

  // แก้ไข todo
  const updateTodo = (id, newText) => {
    setTodos(
      todos.map((todo) => (todo.id === id ? { ...todo, text: newText } : todo)),
    );
  };

  return (
    <div>
      {todos.map((todo) => (
        <div key={todo.id}>
          <span>{todo.text}</span>
          <button onClick={() => deleteTodo(todo.id)}>ลบ</button>
        </div>
      ))}
    </div>
  );
}
```

### ข้อควรรู้

- **ห้ามแก้ state โดยตรง** → `count = 5`
- **ใช้ setter function** → `setCount(5)`
- **State ต้องเป็น immutable** (สร้าง object/array ใหม่)
- **setState เป็น asynchronous** (อัปเดตไม่ทันที)

> **ทำไม immutable ต้องสำคัญ?**
>
> React วัดการเปลี่ยนแปลง โดย**เปรียบเทียบ reference** ไม่ใช่ค่าข้อมูล
>
> ```javascript
> const person = { name: "John", age: 30 };
>
> //  ผิด - reference เดิม React ไม่รู้มีการเปลี่ยนแปลง
> person.age = 31;
> setPerson(person); //  React คิดว่าไม่มีการเปลี่ยนแปลง
>
> //  ถูก - reference ใหม่ React รู้มีการเปลี่ยนแปลง
> setPerson({ ...person, age: 31 }); //  React รู้มีการเปลี่ยนแปลง
> ```
>
> React ตรวจสอบว่า object อันใหม่มาแล้ว แล้วจึง re-render

---

## Side Effects (useEffect)

useEffect = ทำบางอย่างเมื่อ component mount หรือ dependencies เปลี่ยน

### ไวยากรณ์พื้นฐานของ useEffect

```javascript
import { useEffect } from "react";

useEffect(() => {
  // Code ที่ต้องการให้รัน
  console.log("Component mounted!");

  // Cleanup function (optional)
  return () => {
    console.log("Component will unmount");
  };
}, []); // Dependency array
```

### Dependency Array

```javascript
// 1. ไม่มี dependency (รัน 1 ครั้งตอน mount)
useEffect(() => {
  console.log("Component mounted!");
}, []);

// 2. มี dependency (รัน เมื่อ dependency เปลี่ยน)
useEffect(() => {
  console.log(`Count changed: ${count}`);
}, [count]);

// 3. ไม่มี array (รัน ทุกครั้ง component render) - โดยทั่วไปไม่แนะนำ
useEffect(() => {
  console.log("Render!");
});
```

> **Dependency Array คืออะไร?**
>
> ```javascript
> useEffect(() => {
>   // Code ที่รัน
> }, [dependencies]); // ← dependency array
> ```
>
> | Array           | ความหมาย                                         |
> | --------------- | ------------------------------------------------ |
> | `[]`            | รัน 1 ครั้ง ตอนคอมโพเนนต์ถูกสร้าง (mount)        |
> | `[count]`       | รัน เมื่อ `count` เปลี่ยน (ตรวจสอบทุก render)    |
> | `[count, name]` | รัน เมื่อ `count` หรือ `name` เปลี่ยน            |
> | ไม่มี           | รัน ทุกครั้งคอมโพเนนต์ render (ไม่มีประสิทธิภาพ) |
>
> **กฎ:** เพิ่มตัวแปรที่ใช้ในฟังก์ชัน useEffect ลงใน array
>
> ```javascript
> useEffect(() => {
>   console.log(count); // ← ใช้ count
> }, [count]); // ← ต้องใส่ count ที่นี่
> ```

### ตัวอย่าง: Fetch Data

```javascript
function PostList() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchPosts = async () => {
      try {
        const response = await fetch("https://api.example.com/posts");
        const data = await response.json();
        setPosts(data);
        setError(null);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchPosts();
  }, []); // รัน 1 ครั้งตอน mount

  if (loading) return <p>กำลังโหลด...</p>;
  if (error) return <p>เกิดข้อผิดพลาด: {error}</p>;

  return (
    <div>
      {posts.map((post) => (
        <div key={post.id}>{post.title}</div>
      ))}
    </div>
  );
}
```

### Cleanup Function

```javascript
function Timer() {
  useEffect(() => {
    // Setup
    const interval = setInterval(() => {
      console.log("Running...");
    }, 1000);

    // Cleanup - ทำความสะอาดเมื่อ component unmount
    return () => {
      clearInterval(interval);
    };
  }, []);

  return <p>Timer running</p>;
}
```

---

## Event Handling

### หลักการพื้นฐาน

```javascript
function Button() {
  //  ถูก - ส่ง function
  const handleClick = () => {
    console.log("คลิก!");
  };

  return <button onClick={handleClick}>Click</button>;

  //  ผิด - เรียก function ทันที
  // return <button onClick={handleClick()}>Click</button>;

  //  ถูก - ใช้ Arrow function
  // return <button onClick={() => handleClick()}>Click</button>;
}
```

### เหตุการณ์ที่ใช้บ่อย

```javascript
function EventDemo() {
  const handleChange = (e) => {
    console.log("Value:", e.target.value);
  };

  const handleFocus = (e) => {
    console.log("Focused!");
  };

  const handleSubmit = (e) => {
    e.preventDefault(); // ป้องกัน default behavior
    console.log("Form submitted!");
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        onChange={handleChange}  {/* Text changed */}
        onFocus={handleFocus}    {/* Input focused */}
        onBlur={() => console.log("Blurred")}
      />
      <button type="submit">ส่ง</button>
    </form>
  );
}
```

### รายการเหตุการณ์ที่ใช้บ่อย

| เหตุการณ์      | ใช้กับ                  | ตัวอย่าง                                       |
| -------------- | ----------------------- | ---------------------------------------------- |
| `onClick`      | button, div             | `<button onClick={handleClick}>Click</button>` |
| `onChange`     | input, textarea, select | `<input onChange={e => log(e.target.value)}`   |
| `onSubmit`     | form                    | `<form onSubmit={handleSubmit}>`               |
| `onFocus`      | input, textarea         | `<input onFocus={handleFocus}`                 |
| `onBlur`       | input, textarea         | `<input onBlur={handleBlur}`                   |
| `onMouseEnter` | any                     | `<div onMouseEnter={handleEnter}>`             |
| `onMouseLeave` | any                     | `<div onMouseLeave={handleLeave}>`             |
| `onKeyDown`    | input, textarea         | `<input onKeyDown={handleKey}`                 |
| `onKeyUp`      | input, textarea         | `<input onKeyUp={handleKey}`                   |

---

## Conditional Rendering

### if-else

```javascript
function Login({ isLogged }) {
  if (isLogged) {
    return <h1>ยินดีต้อนรับ!</h1>;
  } else {
    return <h1>กรุณาเข้าสู่ระบบ</h1>;
  }
}
```

### Ternary Operator

```javascript
function Login({ isLogged }) {
  return (
    <div>{isLogged ? <h1>ยินดีต้อนรับ</h1> : <h1>กรุณาเข้าสู่ระบบ</h1>}</div>
  );
}
```

### Operator && (แสดงเฉพาะเมื่อเป็นจริง)

```javascript
function Notification({ hasNewMessage }) {
  return <div>{hasNewMessage && <p>คุณมีข้อความใหม่</p>}</div>;
```

### switch-case

```javascript
function Status({ status }) {
  switch (status) {
    case "loading":
      return <p>กำลังโหลด...</p>;
    case "success":
      return <p>สำเร็จ</p>;
    case "error":
      return <p>เกิดข้อผิดพลาด</p>;
    default:
      return <p>สถานะไม่ทราบ</p>;
  }
}
```

---

## Lists & Keys

### การแสดงรายการ (List)

```javascript
function StudentList() {
  const students = [
    { id: 1, name: "สมชาย", grade: "A" },
    { id: 2, name: "สมหญิง", grade: "B" },
    { id: 3, name: "สมศรี", grade: "A" },
  ];

  return (
    <ul>
      {students.map((student) => (
        <li key={student.id}>
          {student.name} - เกรด {student.grade}
        </li>
      ))}
    </ul>
  );
}
```

### เกี่ยวกับคีย์ (Keys)

```javascript
//  ถูก - ใช้ unique ID
<li key={student.id}>{student.name}</li>

//  ใช้ได้ - ใช้ index (ต้องระวัง ถ้า list มีการลบ/เพิ่ม/เรียงลำดับ)
<li key={index}>{student.name}</li>

//  ผิด - ไม่มี key
<li>{student.name}</li>

//  ผิด - key ไม่ unique
{students.map(student => (
  <li key={student.name}>{student.name}</li> // อาจซ้ำกันได้
))}
```

### ความสำคัญของคีย์

- React ใช้ key เพื่อระบุว่า element ไหนเปลี่ยนแปลง
- ถ้าไม่มี key ที่ unique → render ไม่ถูกต้อง
- ส่งผลต่อ state สำหรับแต่ละ item

```javascript
//  ปัญหา - ไม่มี unique key
function TodoList() {
  const [todos, setTodos] = useState([
    { text: "Study React" },
    { text: "Practice JavaScript" },
  ]);

  // ถ้าลบ item แรก → state อาจติดกับ item ผิด
  const deleteTodo = (index) => {
    setTodos(todos.filter((_, i) => i !== index));
  };

  return (
    <ul>
      {todos.map((todo, index) => (
        <li key={index}>{todo.text}</li> //  ผิด
      ))}
    </ul>
  );
}

//  ถูก - มี unique ID
function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: "Study React" },
    { id: 2, text: "Practice JavaScript" },
  ]);

  const deleteTodo = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id));
  };

  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>{todo.text}</li> //  ถูก
      ))}
    </ul>
  );
}
```

---

## Forms

### คอมโพเนนต์ที่ควบคุม (Controlled Component)

```javascript
function LoginForm() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log("ส่ง:", { username, password });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="ชื่อผู้ใช้"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <input
        type="password"
        placeholder="รหัสผ่าน"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">เข้าสู่ระบบ</button>
    </form>
  );
}
```

### หลายอินพุต

```javascript
function SignupForm() {
  const [formData, setFormData] = useState({
    firstName: "",
    lastName: "",
    email: "",
    terms: false,
  });

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setFormData({
      ...formData,
      [name]: type === "checkbox" ? checked : value,
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="firstName"
        value={formData.firstName}
        onChange={handleChange}
        placeholder="ชื่อจริง"
      />
      <input
        name="lastName"
        value={formData.lastName}
        onChange={handleChange}
        placeholder="นามสกุล"
      />
      <input
        name="email"
        type="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="อีเมล"
      />
      <label>
        <input
          name="terms"
          type="checkbox"
          checked={formData.terms}
          onChange={handleChange}
        />
        ยอมรับข้อกำหนด
      </label>
      <button type="submit">สมัครสมาชิก</button>
    </form>
  );
}
```

### องค์ประกอบ Select และ Textarea

```javascript
function RegistrationForm() {
  const [country, setCountry] = useState("Thailand");
  const [bio, setBio] = useState("");

  return (
    <form>
      <select value={country} onChange={(e) => setCountry(e.target.value)}>
        <option value="Thailand">ไทย</option>
        <option value="USA">USA</option>
        <option value="Japan">ญี่ปุ่น</option>
      </select>

      <textarea
        value={bio}
        onChange={(e) => setBio(e.target.value)}
        placeholder="เขียนเกี่ยวกับตัวคุณ"
      />
    </form>
  );
}
```

---

## Common Hooks

### useState - จัดการสถานะท้องถิ่นของคอมโพเนนต์

ใช้เมื่อต้องการ state ที่อัปเดตและ re-render component

```javascript
const [state, setState] = useState(initialValue);
```

### useEffect - จัดการผลข้างเคียง (Side Effects)

ใช้เมื่อต้องการให้บางอย่างทำงาน เช่น fetch data, set title, listen events

```javascript
useEffect(() => {
  // Effect code (fetch, timer, etc.)
  return () => {
    // Cleanup code (optional) - ทำความสะอาดเมื่อ unmount
  };
}, [dependencies]); // re-run ถ้า dependencies เปลี่ยน
```

### useContext - แชร์ข้อมูลระหว่างคอมโพเนนต์

ใช้ global state ที่เก็บใน Context (ไม่ต้องส่ง props ทีละ level)

```javascript
const MyContext = React.createContext();
const value = useContext(MyContext); // ดึงค่าจาก Context
```

> **หมายเหตุ:** ดูตัวอย่างเต็มใน [Context API](#context-api) section

### useReducer - ตรรกะสถานะที่ซับซ้อน

ใช้เมื่อมี state logic ซับซ้อน (หลาย sub-values หรือ dependencies ระหว่าง updates)

**ตัวอย่าง:** Counter ที่มี INCREMENT/DECREMENT/RESET actions

```javascript
function counterReducer(state, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}

function Counter() {
  const [count, dispatch] = useReducer(counterReducer, 0);

  return (
    <>
      <p>{count}</p>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>+</button>
      <button onClick={() => dispatch({ type: "DECREMENT" })}>-</button>
    </>
  );
}
```

---

## Custom Hooks

Custom Hooks คือ function ที่สร้างขึ้นเอง ใช้ React Hooks (เช่น useState, useEffect) เพื่อนำเสนอตรรกะซ้ำใช้ระหว่าง components

### ทำไมต้องใช้ Custom Hooks?

- **เก็บรวม logic ไว้ที่เดียว** - แทนการเขียน useState + useEffect ซ้ำๆ ในหลาย components
- **ซ้ำใช้ได้** - สร้าง hook 1 ครั้ง ใช้ได้ในหลาย components
- **ง่ายต่อการบำรุงรักษา** - เปลี่ยนแปลง logic เพียง 1 ที่ นอกเหนือจากการปรับปรุงทั้ง app
- **ทำ component ให้ clean** - ลดความซับซ้อนในตัว component

### หลักการพื้นฐาน

- **ต้องเริ่มชื่อด้วย `use`** (เช่น `useFormInput`, `useFetch`, `useToggle`)
  - React เรียนรู้ว่านี่คือ Hook และตรวจสอบกฎของ Hook
  - ไม่ต้องเริ่มด้วย `use` = ไม่ใช่ Hook (จะเกิดข้อผิดพลาด)
- **สามารถใช้ built-in Hooks ข้างในได้** (useState, useEffect, useContext, เป็นต้น)
  - ใช้ได้ทั้งหมดเลย
  - Hook ข้างใน custom hook จะทำงานปกติเหมือนใน component
- **ส่งคืนค่าที่ components สามารถใช้ได้**
  - return state, function, หรือ object ที่รวม state + function
  - Component ที่ใช้ custom hook ต้องได้ค่ากลับมา

### ตัวอย่าง 1: useFormInput

**ประโยชน์:** จัดการค่า input ที่ซ้ำๆ กันหลาย inputs

**ปัญหาเดิม:**

```javascript
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [email, setEmail] = useState("");
// ... ซ้ำเดิม 3 ครั้ง
```

**วิธีแก้ด้วย useFormInput:**

```javascript
import { useState } from "react";

// Custom hook
function useFormInput(initialValue) {
  const [value, setValue] = useState(initialValue);

  return {
    value,
    setValue,
    bind: {
      value,
      onChange: (e) => setValue(e.target.value),
    },
  };
}

// ใช้งาน
function LoginForm() {
  const username = useFormInput("");
  const password = useFormInput("");

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(username.value, password.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input {...username.bind} placeholder="Username" />
      <input {...password.bind} type="password" placeholder="Password" />
      <button type="submit">เข้าสู่ระบบ</button>
    </form>
  );
}
```

### ตัวอย่าง 2: useFetch

**ประโยชน์:** ดึงข้อมูลจาก API พร้อมจัดการ loading/error state ใน hook เดียว

**ข้อดี:**

- เขียน fetch logic 1 ครั้ง ใช้ได้หลาย components
- จัดการ state (data, loading, error) บรรจุอยู่ในที่เดียว
- ทำ component สะอาด ไม่เต็มไปด้วย useEffect boilerplate

\*\*Code:

// Custom hook ดึงข้อมูล
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const jsonData = await response.json();
setData(jsonData);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};

    fetchData();

}, [url]);

return { data, loading, error };
}

// ใช้งาน
function PostList() {
const {
data: posts,
loading,
error,
} = useFetch("https://api.example.com/posts");

if (loading) return <p>กำลังโหลด...</p>;
if (error) return <p>เกิดข้อผิดพลาด: {error}</p>;

return (

<ul>
{posts?.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}

```

### ตัวอย่าง 3: useToggle

**ประโยชน์:** สลับ state ระหว่าง true/false (เช่น เปิด/ปิด menu, show/hide modal)

**ทำไมต้องใช้:**
- `useState` ธรรมดา: `setIsOpen(!isOpen)` → ต้องเขียน toggle logic ทุกครั้ง
- `useToggle`: `toggleMenu()` → ง่ายขึ้น สั่นเขียน

**Code:

// Custom hook สำหรับสลับ true/false
function useToggle(initialState = false) {
  const [state, setState] = useState(initialState);

  const toggle = () => setState(!state);

  return [state, toggle];
}

// ใช้งาน
function Menu() {
  const [isOpen, toggleMenu] = useToggle();

  return (
    <div>
      <button onClick={toggleMenu}>{isOpen ? "ปิด" : "เปิด"} เมนู</button>
      {isOpen && (
        <ul>
          <li>หน้าแรก</li>
          <li>เกี่ยวกับ</li>
          <li>ติดต่อ</li>
        </ul>
      )}
    </div>
  );
}
```

---

## Performance Optimization (useCallback & useMemo)

### ปัญหา: Component re-render บ่อยเกินไป

เมื่อ parent render → function และ object ถูกสร้างใหม่ → child ที่ใช้ props เหล่านี้ก็ re-render ด้วย (แม้ค่าจริงๆ ไม่เปลี่ยน)

**ทำไมเป็นปัญหา?**

- Re-render ไม่จำเป็นทำให้ app ช้า
- ถ้ามี animation หรือ calculation ในที่ของมันอาจ lag

```javascript
// ปัญหา: IncreaseButton re-render ทุกครั้ง parent render
function Counter() {
  const [count, setCount] = useState(0);

  // function ใหม่ทุกครั้ง → child re-render (แม้ function ทำสิ่งเดิม)
  const handleIncrease = () => setCount(count + 1);

  return (
    <div>
      <p>Count: {count}</p>
      <IncreaseButton onClick={handleIncrease} />
    </div>
  );
}
```

### memo - ป้องกัน re-render ถ้า props ไม่เปลี่ยน

ใช้ `memo()` เพื่อห่อ component ไม่ให้ re-render เมื่อ props เหมือนเดิม

```javascript
import { memo } from "react";

// ปกติ: re-render ทุกครั้ง parent render
function IncreaseButton({ onClick }) {
  console.log("IncreaseButton render");
  return <button onClick={onClick}>เพิ่ม</button>;
}

// ใช้ memo: re-render เฉพาะ props เปลี่ยน
const IncreaseButton = memo(function IncreaseButton({ onClick }) {
  console.log("IncreaseButton render");
  return <button onClick={onClick}>เพิ่ม</button>;
});
```

### useCallback - เก็บ function เดิมไม่ให้สร้างใหม่

ป้องกัน function ถูกสร้างใหม่ทุกครั้ง component render

**วิธีการ:**

1. ห่อ function ด้วย `useCallback()`
2. ระบุ dependencies ใน array
3. Function จะคืนค่าเดิม ถ้า dependencies ไม่เปลี่ยน

```javascript
import { useCallback, useState, memo } from "react";

const IncreaseButton = memo(function IncreaseButton({ onClick }) {
  console.log("IncreaseButton render");
  return <button onClick={onClick}>เพิ่ม</button>;
});

function Counter() {
  const [count, setCount] = useState(0);

  // useCallback - function เดิม ไม่สร้างใหม่
  const handleIncrease = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []); // dependency array ว่าง = function เดิมตลอด

  return (
    <div>
      <p>{count}</p>
      <IncreaseButton onClick={handleIncrease} />
    </div>
  );
}
```

### useMemo - เก็บค่า (object, array) ที่คำนวณแล้ว

ป้องกัน object/array ที่ซับซ้อนถูกสร้างใหม่ทุกครั้ง

**เมื่อไหร่ต้องใช้:**

- Calculation ที่หนัก (filter, map, sort บน array ใหญ่)
- ส่ง object/array ให้ child ที่ใช้ memo
- ใช้ค่าใน dependency array ของ useEffect

**วิธีการ:**

1. ห่อ calculation ด้วย `useMemo()`
2. ระบุ dependencies
3. ค่าจะคำนวณใหม่ เฉพาะ dependencies เปลี่ยน (ไม่ใช่ทุกครั้ง render)

\*\*Code:

function UserList({ users, filter }) {
// ปัญหา: filteredUsers สร้างใหม่ทุกครั้ง render
// const filteredUsers = users.filter(user => user.name.includes(filter));

// ถูก: useMemo เก็บค่า เมื่อ users หรือ filter เปลี่ยน เท่านั้น
const filteredUsers = useMemo(() => {
console.log("Filtering users...");
return users.filter((user) => user.name.includes(filter));
}, [users, filter]); // recalculate เมื่อ users หรือ filter เปลี่ยน

return (

<ul>
{filteredUsers.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}

````

### เมื่อไหร่ต้องใช้ useCallback และ useMemo?

| สถานการณ์                       | ใช้           | เหตุผล                        |
| ------------------------------- | ------------- | ----------------------------- |
| Child component ใช้ memo        | ✓ useCallback | ป้องกัน unnecessary render    |
| Dependency array ของ useEffect  | ✓ useCallback | function จะเหมือนตลอด         |
| การคำนวณ array/object ซับซ้อน   | ✓ useMemo     | เก็บค่าเพื่อ performance      |
| ส่งค่าให้ child ที่ใช้ memo     | ✓ useMemo     | ป้องกัน object ใหม่           |
| Function จำเป็น (e.g., onClick) | ✓ useCallback | ลดการ re-render               |
| ไม่แน่ใจ                        | ✕ ยังไม่ต้อง  | เพิ่ม complexity โดยไม่จำเป็น |

> **เคล็ดลับ:** ใช้ useCallback/useMemo เมื่อจริงๆ มีปัญหา performance เท่านั้น สำหรับ app เล็กๆ อาจไม่ต้องใช้

---

## Context API

### ทำไมต้องใช้ Context API?

- **ลด Props Drilling** - ไม่ต้องส่ง props ผ่าน component ที่ไม่ใช้มัน
- **แชร์ global state ได้ง่าย** - User info, Theme, Language ฯลฯ
- **Code สะอาดขึ้น** - ไม่มี props ยาวๆ พัวพัวไป
- **Maintainable** - เปลี่ยนแปลง data ในที่เดียว ทั้ง app ใช้ได้

### ปัญหา: Props Drilling

การส่ง props ลงทีละ level มาก ๆ ทำให้ code ยุ่งยากและยากต่อการดูแล

**ตัวอย่างปัญหา:**

```javascript
// ปัญหา: ต้องส่ง theme ผ่าน Middle Component แม้ว่า Middle ไม่ใช้มัน
function App() {
  const [theme, setTheme] = useState("light");
  return <Middle theme={theme} setTheme={setTheme} />;
}

function Middle({ theme, setTheme }) {
  return <Content theme={theme} setTheme={setTheme} />;
}

function Content({ theme, setTheme }) {
  return <div style={{ background: theme }}>Theme: {theme}</div>;
}
````

### วิธีแก้: Context API

สร้าง Context เพื่อแชร์ข้อมูลทั่วทั้ง App โดยไม่ต้องส่ง props

**ขั้นตอน:**

1. **สร้าง Context** - `createContext()` กำหนด shape ของข้อมูล
2. **สร้าง Provider component** - ห่อ children และส่งค่าผ่าน `value`
3. **สร้าง custom hook** - `useXXX()` เพื่อใช้ Context ได้ง่าย และเช็ค error
4. **ห่อ App ด้วย Provider** - ทำให้ทั้ง descendants เข้าถึง Context
5. **ใช้ custom hook ที่ไหนก็ได้** - ไม่ต้องส่ง props หรือห่อ component

**ตัวอย่างเต็ม: Theme (Light/Dark Mode)**

```javascript
import { createContext, useContext, useState } from "react";

// 1. สร้าง Context
const ThemeContext = createContext();

// 2. สร้าง Provider component
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// 3. สร้าง custom hook เพื่อใช้ Context
function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error("useTheme must be used inside ThemeProvider");
  }
  return context;
}

// 4. ใช้ Context ใน App
function App() {
  return (
    <ThemeProvider>
      <Header />
      <Main />
      <Footer />
    </ThemeProvider>
  );
}

// 5. ใช้ useTheme ในที่ไหนก็ได้
function Header() {
  const { theme, setTheme } = useTheme();

  return (
    <header style={{ background: theme === "light" ? "#fff" : "#333" }}>
      <h1>สวัสดี</h1>
      <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
        เปลี่ยนธีม
      </button>
    </header>
  );
}

function Main() {
  const { theme } = useTheme();

  return (
    <main style={{ background: theme === "light" ? "#f5f5f5" : "#1a1a1a" }}>
      <p>เนื้อหาหลัก</p>
    </main>
  );
}

function Footer() {
  const { theme } = useTheme();

  return (
    <footer style={{ background: theme === "light" ? "#ddd" : "#444" }}>
      <p>ท้ายน้ำ</p>
    </footer>
  );
}
```

### ตัวอย่าง: Context สำหรับข้อมูลผู้ใช้

````

### ตัวอย่าง 2: Context สำหรับข้อมูลผู้ใช้

**ประโยชน์:** เก็บข้อมูล user ให้ทั้ง app เข้าถึง ลดการ pass props

**ความเหมือน:** เหมือนตัวอย่าง Theme แต่มี async function (login/logout) ด้วย

**ข้อสำคัญ:**
- State: `user` (ข้อมูลผู้ใช้), `isLoading` (กำลังเข้าสู่ระบบ)
- Function: `login()` (async), `logout()`
- Custom hook: `useUser()` เช็ค error และคืน context

```javascript
const UserContext = createContext();

function UserProvider({ children }) {
  const [user, setUser] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  const login = async (email, password) => {
    setIsLoading(true);
    try {
      const response = await fetch("/api/login", {
        method: "POST",
        body: JSON.stringify({ email, password }),
      });
      const data = await response.json();
      setUser(data);
    } finally {
      setIsLoading(false);
    }
  };

  const logout = () => setUser(null);

  return (
    <UserContext.Provider value={{ user, isLoading, login, logout }}>
      {children}
    </UserContext.Provider>
  );
}

function useUser() {
  const context = useContext(UserContext);
  if (!context) {
    throw new Error("useUser must be used inside UserProvider");
  }
  return context;
}

// ใช้ใน component
function Profile() {
  const { user, logout } = useUser();

  if (!user) return <p>ยังไม่ได้เข้าสู่ระบบ</p>;

  return (
    <div>
      <h1>{user.name}</h1>
      <button onClick={logout}>ออกจากระบบ</button>
    </div>
  );
}
````

### ข้อควรรู้ Context API

| ข้อ                     | รายละเอียด / ตัวอย่าง                                                       |
| ----------------------- | --------------------------------------------------------------------------- |
| **ส่วนสำคัญ**           | Context ช่วยลดการส่ง props มากเกินไป (props drilling problem)               |
| **Custom Hook**         | สร้าง custom hook (เช่น `useTheme()`) เพื่อใช้ Context ง่ายขึ้น (แนะนำเสมอ) |
| **Error Checking**      | ตรวจสอบ `useContext()` ไม่ได้ null เพื่อหลีกเลี่ยง bug                      |
| **Performance**         | Component ทั้งหมดใน Provider re-render เมื่อ context value เปลี่ยน (อาจช้า) |
| **Optimization Tip**    | ถ้า re-render บ่อยเกิน แบ่ง Context เป็นหลายๆ Provider                      |
| **ใช้ร่วมกับ useState** | ส่วนใหญ่ Context + useState ก็เพียงพอ (ไม่ต้อง Redux ทันที)                 |
| **State Management**    | สำหรับ global state ที่ซับซ้อนมากๆ (หลาย contexts) อาจใช้ Redux/Zustand     |

**ตัวอย่าง: เมื่อไหร่ควรใช้ Context API?**

- ✓ Theme / Language (เปลี่ยนไม่บ่อย)
- ✓ User info / Auth state
- ✓ UI settings (sidebar open/close)
- ✕ Form input state (เปลี่ยนบ่อยเกิน → ใช้ useState ในตัว component)
- ✕ Real-time data (stocks, chat messages → ใช้ state management library)

> **สรุป:** Context API ใช้สำหรับแชร์ข้อมูลข้ามหลายๆ component โดยไม่ต้องส่ง props ทีละ level เหมาะสำหรับ global state ที่ค่อนข้างนิ่ง

---

## Best Practices

### 1. โครงสร้างคอมโพเนนต์

**วิธีการ:** Render state ที่จำเป็น ให้ data flow ชัดเจน

**ข้อดี:** ง่ายต่อการ debug และแยก concern

```javascript
//  ที่ดี - ข้อมูลอัปเดตเมื่อ userId เปลี่ยน
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetchUser(userId).then(setUser);
  }, [userId]);

  if (!user) return <p>Loading...</p>;

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.bio}</p>
    </div>
  );
}
```

### 2. การตั้งชื่อตัวแปร

**วิธีการ:** ใช้ชื่อที่อธิบายเจตนา (intention-revealing names)

**ข้อดี:** โค้ดอ่านง่าย ฟีเจอร์ใจสตาร์ท

```javascript
//  ชื่อชัดเจน - รู้ว่าค่านี้เป็น boolean state
const [isLoading, setIsLoading] = useState(false);
const [errorMessage, setErrorMessage] = useState("");

//  ไม่ชัดเจน - unclear names
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
```

### 3. รักษาคอมโพเนนต์ให้มีขนาดเล็ก

**วิธีการ:** แแยก component ใหญ่ออกเป็น component เล็กๆ

**ข้อดี:** ง่ายต่อการอ่าน, test, และ reuse

```javascript
//  ไม่ดี - Component ใหญ่เกินไป ยากต่อการดูแล
function Dashboard() {
  return (
    <div>
      {/* Profile section */}
      {/* Settings section */}
      {/* Stats section */}
      {/* Lots of code... */}
    </div>
  );
}

//  ดี - แยกเป็น component เล็กๆ ที่มี responsibility เดียว
function Dashboard() {
  return (
    <div>
      <Profile />
      <Settings />
      <Stats />
    </div>
  );
}
```

### 4. อย่าเรียก Hooks แบบมีเงื่อนไข

**ทำไมต้อง:** React ใช้ Hook order เพื่อ track state ถ้า hook runtime เปลี่ยน → state สับสน

**วิธีการที่ถูก:** เรียก hook ก่อนตัดสิน condition ใช้condition แล้วเท่านั้น

```javascript
//  ผิด - Hook ในเงื่อนไข → order เปลี่ยน → bug!
function Component({ condition }) {
  if (condition) {
    const [state, setState] = useState(0); //  ห้าม!
  }
}

//  ถูก - Hook เอา condition logic ขึ้นมา
function Component({ condition }) {
  const [state, setState] = useState(0);

  if (condition) {
    // ใช้ state ในนี้ได้
    setState(state + 1);
  }
}
```

### 5. ป้องกันการรั่วไหลของหน่วยความจำ (Memory Leaks)

**ทำไมต้อง:** Listener, interval, subscription ต้องเอาออกเมื่อ component unmount ไม่เช่นนั้นจะ waste memory

**วิธีการ:** ใช้ cleanup function ใน useEffect

```javascript
//  ผิด - interval ยังคงทำงาน เมื่อ component unmount
function Timer() {
  useEffect(() => {
    const interval = setInterval(() => {
      console.log("tick");
    }, 1000);
    // ไม่มี cleanup - interval ยังคงทำงาน → memory leak
  }, []);
}

//  ถูก - clear interval เมื่อ unmount
function Timer() {
  useEffect(() => {
    const interval = setInterval(() => {
      console.log("tick");
    }, 1000);

    return () => clearInterval(interval); //  cleanup ← สำคัญ!
  }, []);
}
```

### 6. ใช้การอัปเดตสถานะแบบ Immutable

**ทำไมต้อง:** React ตรวจสอบ reference ไม่ใช่ค่า ถ้าแก้ object โดยตรง React คิดว่าไม่เปลี่ยน

**วิธีการ:** สร้าง object/array ใหม่ แล้วส่งให้ setState

```javascript
//  ผิด - แก้ state โดยตรง → React ไม่รู้มีการเปลี่ยน
const handleClick = () => {
  user.name = "New Name";
  setUser(user); //  React คิดว่า user เหมือนเดิม → ไม่ re-render
};

//  ถูก - สร้าง object ใหม่ (spread operator)
const handleClick = () => {
  setUser({ ...user, name: "New Name" });
};

//  ถูก - array
const handleAddTodo = (text) => {
  setTodos([...todos, { id: Date.now(), text }]);
};
```

### 7. ใช้ memo สำหรับ Component ที่ Expensive ในการ Render

**ทำไมต้อง:** Re-render ที่ไม่จำเป็นทำให้ app ช้า โดยเฉพาะ component ที่มี calculation หนัก

**วิธีการ:** ห่อ component ด้วย `memo()` ไม่ให้ re-render ถ้า props เหมือนเดิม

```javascript
import { memo } from "react";

//  ปกติ - re-render ทุกครั้ง parent render (แม้ props ไม่เปลี่ยน)
function UserCard({ user }) {
  console.log("UserCard render");
  return <div>{user.name}</div>;
}

//  ใช้ memo - re-render เฉพาะ props เปลี่ยน
const UserCard = memo(function UserCard({ user }) {
  console.log("UserCard render - only if props changed");
  return <div>{user.name}</div>;
});
```

> **เคล็ดลับ:** ใช้ memo เมื่อมี performance problem จริงๆ (ตรวจสอบด้วย React DevTools Profiler) ไม่ใช่ "just in case"

---

## Quick Reference - การเขียน React

| กรณี            | วิธีทำ                                                             |
| --------------- | ------------------------------------------------------------------ |
| สร้าง component | `function ComponentName() { return <div>...</div>; }`              |
| รับ props       | `function Card({ title, content }) { }`                            |
| State ธรรมดา    | `const [count, setCount] = useState(0);`                           |
| State object    | `const [form, setForm] = useState({ name: "", email: "" });`       |
| สร้าง list      | `items.map(item => <li key={item.id}>{item.text}</li>)`            |
| Event handler   | `<button onClick={() => setCount(count + 1)}>+</button>`           |
| Fetch data      | `useEffect(() => { fetch(...).then(...); }, []);`                  |
| Conditional     | `{isReady ? <Ready /> : <Loading />}`                              |
| Form input      | `<input value={state} onChange={e => setState(e.target.value)} />` |

---

## ขั้นตอนการทำงาน

```
User Interaction
      ↓
Event Handler (onClick, onChange, etc.)
      ↓
setState() called
      ↓
State Updated
      ↓
Component Re-render
      ↓
New UI displayed
```

---

## Checklist ก่อนส่ง Code

- [ ] Component ตั้งชื่อ PascalCase
- [ ] Props ที่ส่งมาตั้งชื่อชัดเจน
- [ ] State ที่เปลี่ยนแปลงใช้ useState
- [ ] Side effects (fetch, timer) ใช้ useEffect
- [ ] List มี unique keys
- [ ] Form input เป็น controlled component
- [ ] Event handlers ตั้งชื่อ handleXxx
- [ ] ไม่มี memory leaks (cleanup in useEffect)
- [ ] Props immutable (ไม่แก้โดยตรง)
- [ ] Component ไม่ใหญ่เกินไป

---

## สรุปประเด็นใหญ่สำหรับผู้เรียน

### หากมีเวลาเพียง 5 นาที ให้อ่านส่วนนี้:

1. **React = UI ที่อัปเดตตัวเองอัตโนมัติ**
   - พอ state เปลี่ยน → React render ใหม่ครั้งเดียว เสร็จ

2. **ขั้นตอน 3 ขั้น ตลอดเวลา:**
   - User โต้ตอบ (click, type, เป็นต้น)
   - ฟังก์ชัน event handler รัน
   - setState() ถูกเรียก → UI อัปเดต

3. **ไม่จำเป็นต้องจำ syntax ทั้งหมด** - ค้นหาได้ทุกเวลา
   - **ควรจำ:** Component, Props, useState, useEffect

4. **ลำดับการเรียน:**
   - ทำตามสารบัญ จาก "การติดตั้ง" ไปยัง "Best Practices"
   - ทำตัวอย่างโค้ดด้วยมือเอง (อย่า copy-paste)
   - ทดลองแก้ไข code เพื่อดูผลการเปลี่ยนแปลง

5. **หากยังสับสน:**
   - ค้นหาส่วนที่ไม่เข้าใจในเอกสารนี้
   - ลองตัวอย่างโค้ดใน Codepen หรือ Codesandbox
   - ถามเพื่อนหรือใช้ ChatGPT เพื่อเข้าใจลึกขึ้น

### ทัศนคติที่สำคัญ:

| ไม่ถูกต้อง                         | ถูกต้อง                       |
| ---------------------------------- | ----------------------------- |
| จำ syntax ทั้งหมด                  | ฝึกอย่างต่อเนื่อง จะจำเอง     |
| เรียน 1-2 ชั่วโมง แล้วคิดว่าจบแล้ว | ฝึกอย่างต่อเนื่อง 1-2 สัปดาห์ |
| ดู tutorial แล้วคิดว่าเรียนแล้ว    | ทำด้วยมือเอง เพื่อความลึก     |
| กลัวผิด ไม่ลองผิด                  | ลองผิด หลายครั้ง คือการเรียน  |

**สำคัญที่สุด:** ฝึกฝนอย่างสม่ำเสมอ ฝึกฝนอย่างสม่ำเสมอ ฝึกฝนอย่างสม่ำเสมอ
