# สัปดาห์ที่ 14 - React #4: Router & Deployment

## สารบัญ

1. [React Router - Navigation ระหว่าง Pages](#1-react-router---navigation-ระหว่าง-pages)
   - [React Router คืออะไร?](#react-router-คืออะไร)
   - [ประเด็นสำคัญ](#ประเด็นสำคัญ)
   - [การติดตั้ง React Router](#การติดตั้ง-react-router)
   - [โครงสร้างพื้นฐาน](#โครงสร้างพื้นฐาน)
   - [องค์ประกอบหลัก: Routes, Route, Link](#องค์ประกอบหลัก-routes-route-link)
   - [ตัวอย่างที่ 1: Simple Routing](#ตัวอย่างที่-1-simple-routing)
   - [ตัวอย่างที่ 2: สร้าง Pages](#ตัวอย่างที่-2-สร้าง-pages)
   - [ตัวอย่างที่ 3: Dynamic Routes](#ตัวอย่างที่-3-dynamic-routes)
   - [Hook ของ React Router](#hook-ของ-react-router)

2. [useContext - State Sharing](#2-usecontext---state-sharing)
   - [useContext คืออะไร?](#usecontext-คืออะไร)
   - [ปัญหา: Props Drilling](#ปัญหา-props-drilling)
   - [ประเด็นสำคัญ](#ประเด็นสำคัญ-1)
   - [ตัวอย่าง: Dark Mode Theme](#ตัวอย่าง-dark-mode-theme)
   - [ตัวอย่าง: Authentication Context](#ตัวอย่าง-authentication-context)

3. [Deployment - ส่งแอปไปออนไลน์](#3-deployment---ส่งแอปไปออนไลน์)
   - [Deployment คืออะไร?](#deployment-คืออะไร)
   - [การ Deploy ไป Vercel](#การ-deploy-ไป-vercel)
   - [การ Deploy ไป Netlify](#การ-deploy-ไป-netlify)
   - [Checklist ก่อน Deploy](#checklist-ก่อน-deploy)
   - [Security - API Keys & Secrets](#security---api-keys--secrets)

4. [ตัวอย่าง: Multi-page React App](#ตัวอย่าง-multi-page-react-app)
   - [โครงสร้าง](#โครงสร้าง)
   - [ตัวอย่าง: App.jsx](#ตัวอย่าง-appjsx)
   - [ตัวอย่าง: Navigation.jsx](#ตัวอย่าง-navigationjsx)
   - [ตัวอย่าง: Home.jsx](#ตัวอย่าง-homejsx)
   - [ตัวอย่าง: UserDetail.jsx](#ตัวอย่าง-userdetailjsx)

5. [สรุป](#สรุปสัปดาห์ที่-14)
6. [บ่อยทำผิด](#บ่อยทำผิด-common-mistakes)
7. [Deployment Troubleshooting](#deployment---troubleshooting)
8. [Practice Exercises](#practice-exercises)
9. [ขั้นตอนถัดไป](#ขั้นตอนถัดไป)
10. [Resources](#resources)

---

## 1. React Router - Navigation ระหว่าง Pages

### React Router คืออะไร?

บทนี้จะนำเสนอวิธีการสร้างเว็บแอปแบบหลายหน้า (Multi-page Application) โดยใช้ React Router เพื่อให้สามารถเปลี่ยน URL และแสดงหน้าต่างๆ ได้โดยไม่ต้อง reload หน้า

### ประเด็นสำคัญ

**React Router** คือไลบรารี่ที่ช่วยให้สร้างเว็บแอปพลิเคชันแบบหลายหน้า (Multi-page) เมื่อ URL เปลี่ยน โดยไม่ต้อง reload หน้า

### การติดตั้ง React Router

```bash
npm install react-router-dom
```

### โครงสร้างพื้นฐาน

```javascript
// src/main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App.jsx";

ReactDOM.createRoot(document.getElementById("root")).render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
);
```

### องค์ประกอบหลัก: Routes, Route, Link

#### 1. Routes - คอนเทนเนอร์สำหรับการกำหนดเส้นทาง

**Routes** คือ Component ที่ห่อหุ้ม Route ทั้งหมด มันจะตรวจสอบ URL ปัจจุบันและเลือก Route ที่ตรงกัน

```javascript
<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/about" element={<About />} />
  <Route path="/contact" element={<Contact />} />
</Routes>
```

**สิ่งที่ Routes ทำ:**

- ตรวจสอบ URL ปัจจุบัน
- หา Route ที่ `path` ตรงกับ URL
- แสดง `element` ของ Route ที่ตรงกัน
- ใช้ได้เพียง 1 Route เท่านั้นต่อครั้ง (ไม่ต้องรีเฟรชหน้า)

#### 2. Route - กำหนด path และ element

**Route** คือ Component ที่กำหนดว่า URL ใดจะแสดง Component ใด

| Props     | ความหมาย                        | ตัวอย่าง              |
| --------- | ------------------------------- | --------------------- |
| `path`    | URL path ที่จะจัดเรียง          | `"/about"`            |
| `element` | Component ที่จะแสดง             | `<About />`           |
| `index`   | กำหนด Route เริ่มต้น (path="/") | `<Route index ... />` |

**ตัวอย่างการใช้:**

```javascript
{
  /* URL: http://example.com/ */
}
<Route path="/" element={<Home />} />;

{
  /* URL: http://example.com/about */
}
<Route path="/about" element={<About />} />;

{
  /* URL: http://example.com/user/123 */
}
<Route path="/user/:id" element={<UserDetail />} />;

{
  /* URL: http://example.com/settings/profile */
}
<Route path="/settings/profile" element={<Settings />} />;
```

**Path ที่พิเศษ:**

- `:id` - Dynamic parameter (เช่น `/user/1`, `/user/2`)
- `*` - Wildcard (หน้า 404 - ต้องอยู่ท้ายสุด)

```javascript
<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/user/:id" element={<UserDetail />} />
  <Route path="*" element={<NotFound />} /> {/* 404 Page */}
</Routes>
```

#### 3. Link - สร้างลิงค์ที่ไม่ reload หน้า

**Link** คล้ายกับ `<a>` ธรรมดา แต่ React Router จะเปลี่ยน URL โดยไม่ reload หน้า (SPA: Single Page Application)

**เปรียบเทียบ Link กับ `<a>`:**

| ลักษณะ     | `<a>`        | `<Link>`     |
| ---------- | ------------ | ------------ |
| รีเฟรชหน้า | รีเฟรช       | ไม่รีเฟรช    |
| Component  | HTML element | React Router |
| ความเร็ว   | ช้า          | เร็ว         |
| State      | หาย (reload) | เก็บไว้      |
| SEO        | ดี           | ดี           |

**ตัวอย่างการใช้:**

```javascript
{/* ถูกต้อง - ใช้ Link */}
<Link to="/">หน้าแรก</Link>
<Link to="/about">เกี่ยวกับ</Link>
<Link to={`/user/${userId}`}>ดูรายละเอียด</Link>

{/* ผิด - ใช้ <a> */}
<a href="/">หน้าแรก</a>

{/* Link กับ CSS class */}
<Link
  to="/about"
  className={isActive ? "active" : ""}
  style={{ color: "white", textDecoration: "none" }}
>
  เกี่ยวกับ
</Link>
```

**Props ที่สำคัญของ Link:**

| Prop    | ความหมาย              | ตัวอย่าง            |
| ------- | --------------------- | ------------------- |
| `to`    | ไปยัง URL ใด (บังคับ) | `to="/about"`       |
| `style` | ตกแต่งการแสดงผล       | `style={{...}}`     |
| `title` | Tooltip เมื่อ hover   | `title="ไปหน้าแรก"` |

### ตัวอย่างที่ 1: Simple Routing

```javascript
// src/App.jsx
import { Routes, Route, Link } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";

export default function App() {
  return (
    <div>
      <nav
        style={{
          backgroundColor: "#333",
          padding: "20px",
          display: "flex",
          gap: "20px",
        }}
      >
        <Link to="/" style={{ color: "white", textDecoration: "none" }}>
          Home
        </Link>
        <Link to="/about" style={{ color: "white", textDecoration: "none" }}>
          About
        </Link>
        <Link to="/contact" style={{ color: "white", textDecoration: "none" }}>
          Contact
        </Link>
      </nav>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>
    </div>
  );
}
```

### ตัวอย่างที่ 2: สร้าง Pages

```javascript
// src/pages/Home.jsx
export default function Home() {
  return (
    <div style={{ padding: '20px' }}>
      <h1>หน้าแรก</h1>
      <p>ยินดีต้อนรับเข้าสู่เว็บไซต์ของเรา</p>
    </div>
  )
}

// src/pages/About.jsx
export default function About() {
  return (
    <div style={{ padding: '20px' }}>
      <h1>เกี่ยวกับเรา</h1>
      <p>เราคือบริษัท XYZ ที่พัฒนาแอปพลิเคชัน</p>
    </div>
  )
}

// src/pages/Contact.jsx
export default function Contact() {
  return (
    <div style={{ padding: '20px' }}>
      <h1>ติดต่อเรา</h1>
      <p>Email: contact@example.com</p>
      <p>Phone: 0123456789</p>
    </div>
  )
}
```

### ตัวอย่างที่ 3: Dynamic Routes

```javascript
// src/App.jsx
import { Routes, Route, Link } from 'react-router-dom'
import UserDetail from './pages/UserDetail'

export default function App() {
  const users = [
    { id: 1, name: 'สมชาย' },
    { id: 2, name: 'สมหญิง' }
  ]

  return (
    <div>
      <nav>
        <Link to="/">หน้าแรก</Link>
      </nav>

      <Routes>
        <Route path="/" element={
          <div>
            <h1>ผู้ใช้ทั้งหมด</h1>
            <ul>
              {users.map(user => (
                <li key={user.id}>
                  <Link to={`/user/${user.id}`}>
                    {user.name}
                  </Link>
                </li>
              ))}
            </ul>
          </div>
        } />
        <Route path="/user/:id" element={<UserDetail />} />
      </Routes>
    </div>
  )
}

// src/pages/UserDetail.jsx
import { useParams } from 'react-router-dom'

export default function UserDetail() {
  const { id } = useParams()

  const users = {
    1: { name: 'สมชาย', email: 'somchai@example.com' },
    2: { name: 'สมหญิง', email: 'somying@example.com' }
  }

  const user = users[id]

  return (
    <div style={{ padding: '20px' }}>
      <h1>{user?.name}</h1>
      <p>{user?.email}</p>
    </div>
  )
}
```

### Hook ของ React Router

React Router มี Hook ที่สำคัญ 3 ตัวที่ช่วยให้ทำงานกับ routing ได้ง่ายขึ้น

| Hook            | ความหมาย                 |
| --------------- | ------------------------ |
| `useParams()`   | อ่านข้อมูลจาก URL params |
| `useNavigate()` | นำทางไปหน้าอื่น          |
| `useLocation()` | อ่านตำแหน่ง URL ปัจจุบัน |

#### 1. useParams() - อ่านข้อมูลจาก URL

**ความหมาย:** ดึงข้อมูล parameter จาก URL เช่น `/user/123` ได้ `id = 123`

**ตัวอย่างการใช้:**

```javascript
// src/App.jsx
import { Routes, Route } from 'react-router-dom'
import UserDetail from './pages/UserDetail'

export default function App() {
  return (
    <Routes>
      <Route path="/user/:id/:name" element={<UserDetail />} />
    </Routes>
  )
}

// src/pages/UserDetail.jsx
import { useParams } from 'react-router-dom'

export default function UserDetail() {
  const { id, name } = useParams()

  return (
    <div>
      <h1>ผู้ใช้: {name}</h1>
      <p>ID: {id}</p>
    </div>
  )
}

// URL: http://localhost:5173/user/42/johndoe
// Output: ผู้ใช้: johndoe, ID: 42
```

#### 2. useNavigate() - นำทางไปหน้าอื่น

**ความหมาย:** ใช้เพื่อเปลี่ยนหน้าแบบ programmatic (ผ่านการคลิกปุ่มหรือสถานการณ์อื่นๆ)

**ตัวอย่างการใช้:**

```javascript
// src/pages/Login.jsx
import { useNavigate } from "react-router-dom";

export default function Login() {
  const navigate = useNavigate();

  function handleLogin() {
    // ตรวจสอบข้อมูล...
    alert("เข้าสู่ระบบสำเร็จ!");

    // นำทางไปหน้าแรก
    navigate("/");

    // หรือกลับไปหน้าก่อนหน้า
    // navigate(-1)
  }

  return (
    <div style={{ padding: "20px" }}>
      <h1>เข้าสู่ระบบ</h1>
      <button onClick={handleLogin}>เข้าสู่ระบบ</button>
    </div>
  );
}
```

**ตัวอย่าง useNavigate() ขั้นสูง:**

```javascript
import { useNavigate } from "react-router-dom";

export default function DeleteUser() {
  const navigate = useNavigate();

  function handleDelete() {
    // ลบข้อมูล...

    // นำทางไปหน้าอื่นพร้อมผ่าน state
    navigate("/users-list", {
      state: { message: "ลบผู้ใช้สำเร็จแล้ว" },
    });

    // หรือกลับไป 2 หน้าก่อนหน้า
    // navigate(-2)
  }

  return <button onClick={handleDelete}>ลบผู้ใช้</button>;
}
```

**Method ของ navigate:**

- `navigate('/')` - ไปยัง path ที่ระบุ
- `navigate(-1)` - กลับไปหน้าก่อนหน้า (เหมือน back button)
- `navigate('/path', { replace: true })` - แทนที่ history แทนการเพิ่ม

#### 3. useLocation() - อ่าน URL ปัจจุบัน

**ความหมาย:** ดึงข้อมูล URL ปัจจุบันและ query string

**ตัวอย่างการใช้:**

```javascript
import { useLocation } from "react-router-dom";

export default function CurrentPageInfo() {
  const location = useLocation();

  return (
    <div>
      <p>Path ปัจจุบัน: {location.pathname}</p>
      <p>Search: {location.search}</p>
      <p>Hash: {location.hash}</p>
      <p>State: {JSON.stringify(location.state)}</p>
    </div>
  );
}

// URL: http://localhost:5173/about?page=1&sort=name#section
// Output:
// Path ปัจจุบัน: /about
// Search: ?page=1&sort=name
// Hash: #section
// State: null
```

#### 4. Performance - Code Splitting & Lazy Loading

**ปัญหา:** React app ใหญ่ๆ จะ load ทั้ง bundle เมื่อเข้าแรกครั้ง (ช้า)

**วิธีแก้:** ใช้ `React.lazy()` เพื่อ split code per route

```javascript
import { lazy, Suspense } from "react";
import { Routes, Route } from "react-router-dom";

// ❌ ปกติ - load ทั้งหมดเลย
// import Home from './pages/Home'
// import About from './pages/About'
// import Products from './pages/Products'

// ✅ ถูกต้อง - load เฉพาะที่ต้อง ใช้ที่
const Home = lazy(() => import("./pages/Home"));
const About = lazy(() => import("./pages/About"));
const Products = lazy(() => import("./pages/Products"));

function LoadingSpinner() {
  return <div>กำลังโหลด...</div>;
}

export default function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/products" element={<Products />} />
      </Routes>
    </Suspense>
  );
}

// ผลลัพธ์:
// - Initial load: Home component เท่านั้น
// - เมื่อไปหน้า /about: Download About component
// - เมื่อไปหน้า /products: Download Products component
```

**ประโยชน์:**

- Initial load เร็วขึ้นมาก (speed boost)
- แสดง Loading indicator ขณะดาวน์โหลด component
- Smooth user experience สำหรับ large apps

**ตัวอย่าง: ใช้ query string เพื่อกรองข้อมูล**

```javascript
import { useSearchParams } from "react-router-dom";

export default function ProductList() {
  const [searchParams, setSearchParams] = useSearchParams();

  const category = searchParams.get("category") || "all";
  const sort = searchParams.get("sort") || "newest";
  const page = parseInt(searchParams.get("page") || "1");

  // ข้อมูลตัวอย่าง
  const products = [
    { id: 1, name: "Laptop", category: "electronics", price: 999 },
    { id: 2, name: "T-Shirt", category: "clothing", price: 29 },
    { id: 3, name: "Book", category: "books", price: 15 },
  ];

  // กรองสินค้าตามหมวดหมู่
  let filtered =
    category === "all"
      ? products
      : products.filter((p) => p.category === category);

  // เรียงลำดับ
  if (sort === "price") {
    filtered = [...filtered].sort((a, b) => a.price - b.price);
  } else if (sort === "newest") {
    filtered = [...filtered].reverse();
  }

  function handleCategoryChange(newCategory) {
    setSearchParams({ category: newCategory, sort, page: "1" });
  }

  function handleSort(newSort) {
    setSearchParams({ category, sort: newSort, page: "1" });
  }

  return (
    <div>
      <h1>ร้านค้า</h1>

      <div style={{ marginBottom: "20px" }}>
        <label>
          หมวดหมู่:
          <select
            value={category}
            onChange={(e) => handleCategoryChange(e.target.value)}
          >
            <option value="all">ทั้งหมด</option>
            <option value="electronics">อิเล็กทรอนิกส์</option>
            <option value="clothing">เสื้อผ้า</option>
            <option value="books">หนังสือ</option>
          </select>
        </label>
      </div>

      <div style={{ marginBottom: "20px" }}>
        <label>
          เรียงลำดับ:
          <select value={sort} onChange={(e) => handleSort(e.target.value)}>
            <option value="newest">ใหม่ล่าสุด</option>
            <option value="price">ราคาต่ำสุด</option>
          </select>
        </label>
      </div>

      <p>พบ {filtered.length} รายการ</p>
      <ul>
        {filtered.map((product) => (
          <li key={product.id}>
            {product.name} - ${product.price}
          </li>
        ))}
      </ul>
    </div>
  );
}

// URL ตัวอย่าง: http://localhost:5173/shop?category=electronics&sort=price&page=1
// URL ที่สร้างโดย setSearchParams สะอาดและปลอดภัย
```

---

## 2. useContext - State Sharing

### useContext คืออะไร?

บทนี้จะนำเสนอวิธีหลีกเลี่ยง Props Drilling โดยแชร์ State แบบ Global State ด้วย Context API เช่น Dark Mode, ข้อมูลผู้ใช้ หรือการเปลี่ยนภาษา

### ประเด็นสำคัญ

**useContext** ช่วยให้แชร์ข้อมูล (State) ระหว่าง Components โดยไม่ต้องส่ง Props ทีละตัว

**แนวคิดพื้นฐาน:**

Context API ประกอบด้วยส่วนสำคัญ 3 ส่วน:

1. **Context Object** - ภาชนะเก็บข้อมูลแบบ Global
2. **Provider** - ส่วนที่ให้ข้อมูล (ห่อ Components)
3. **Consumer (useContext hook)** - ส่วนที่รับ/ใช้ข้อมูล

**ความไหลของข้อมูล:**

```
Provider (มี state)
  ↓ ส่ง value ผ่าน Context.Provider
  ├─ Component A → useContext() ← ดึงข้อมูล
  ├─ Component B → useContext() ← ดึงข้อมูล
  └─ Component C
      ├─ Component D → useContext() ← ดึงข้อมูล
      └─ Component E → useContext() ← ดึงข้อมูล
```

**วิธีการทำงาน:**

```javascript
// 1. สร้าง Context object
const ThemeContext = createContext();
// createContext(defaultValue) return object ที่มี .Provider และ .Consumer

// 2. สร้าง Provider component ห่อ state
function ThemeProvider({ children }) {
  const [isDark, setIsDark] = useState(false);

  return (
    // ส่ง value ผ่าน Provider
    <ThemeContext.Provider value={{ isDark, setIsDark }}>
      {children}
    </ThemeContext.Provider>
  );
}

// 3. ใช้ useContext ใน Component ต่างๆ
function Button() {
  const { isDark } = useContext(ThemeContext);
  // ได้ค่าจาก value prop!
}
```

**ข้อดีของ useContext:**

| ด้าน        | ข้อดี                                                   |
| ----------- | ------------------------------------------------------- |
| ความสะดวก   | ไม่ต้องส่ง props ขั้นต่ อ ↔ Component ที่ต้องใช้ดึงตรงๆ |
| Readability | Code ชัดเจน ไม่มี props ที่ไม่ดูเหมือนจะใช้             |
| Maintenance | เปลี่ยน structure ได้ง่ายขึ้น                           |
| Performance | Avoid unnecessary re-renders (ถ้าใช้ useMemo)           |

**ข้อควรระวัง:**

- Context ทำให้ Component อ่านยาก (implicit dependencies)
- ทำให้ Testing ยากขึ้นเพราะต้อง mock Provider
- ไม่ใช่ทดแทน State Management Library เมื่อข้อมูลซับซ้อน

### ปัญหา: Props Drilling

ก่อนใช้ useContext จะเกิดปัญหา Props Drilling เมื่อต้องส่ง props ผ่าน components หลายชั้น:

**ตัวอย่าง Props Drilling ที่ไม่ดี:**

```javascript
// src/App.jsx
export default function App() {
  const [isDark, setIsDark] = useState(false);
  const [language, setLanguage] = useState("th");

  // ต้องส่ง isDark และ setIsDark ผ่านทุก layer!
  return (
    <Page isDark={isDark} setIsDark={setIsDark} language={language}>
      <Header isDark={isDark} setIsDark={setIsDark} language={language}>
        <Nav isDark={isDark} setIsDark={setIsDark} language={language}>
          <Button isDark={isDark} setIsDark={setIsDark} language={language} />
        </Nav>
      </Header>
    </Page>
  );
}

// src/components/Header.jsx
function Header({ isDark, setIsDark, language }) {
  // ได้ props แล้วแต่ไม่ใช้ มีแต่ส่งต่อให้ child
  return (
    <header>
      <Nav isDark={isDark} setIsDark={setIsDark} language={language} />
    </header>
  );
}

// src/components/Nav.jsx
function Nav({ isDark, setIsDark, language }) {
  // ได้ props แล้วแต่ไม่ใช้ มีแต่ส่งต่อให้ child
  return (
    <nav>
      <Button isDark={isDark} setIsDark={setIsDark} language={language} />
    </nav>
  );
}

// src/components/Button.jsx
function Button({ isDark, setIsDark, language }) {
  //  จึงใช้ props ที่นี่
  return (
    <button
      onClick={() => setIsDark(!isDark)}
      style={{ color: isDark ? "white" : "black" }}
    >
      {isDark ? "Light" : "Dark"}
    </button>
  );
}
```

**ปัญหาที่เกิดขึ้น:**

1. Props ต้องผ่าน Header → Nav → Button (เหมือนซ้อนโดยไม่จำเป็น)
2. Header และ Nav ไม่ได้ใช้จริง แค่ส่งต่อ
3. ถ้าเปลี่ยน prop name ต้องไปแก้ทุก layer
4. ไม่รู้ว่า props ไปที่ไหนในที่สุด

**วิธีแก้ด้วย useContext:**

```javascript
// src/ThemeContext.jsx
import { createContext, useState } from "react";

export const ThemeContext = createContext();
export const LanguageContext = createContext();

export function ThemeProvider({ children }) {
  const [isDark, setIsDark] = useState(false);

  return (
    <ThemeContext.Provider value={{ isDark, setIsDark }}>
      {children}
    </ThemeContext.Provider>
  );
}

export function LanguageProvider({ children }) {
  const [language, setLanguage] = useState("th");

  return (
    <LanguageContext.Provider value={{ language, setLanguage }}>
      {children}
    </LanguageContext.Provider>
  );
}

// src/App.jsx
export default function App() {
  return (
    <ThemeProvider>
      <LanguageProvider>
        <Page />
      </LanguageProvider>
    </ThemeProvider>
  );
}

// src/components/Header.jsx
function Header() {
  // ไม่ต้องรับ props เลย
  return (
    <header>
      <Nav />
    </header>
  );
}

// src/components/Nav.jsx
function Nav() {
  // ไม่ต้องรับ props เลย
  return (
    <nav>
      <Button />
    </nav>
  );
}

// src/components/Button.jsx
import { useContext } from "react";
import { ThemeContext, LanguageContext } from "../ThemeContext";

function Button() {
  // ดึงมาโดยตรง! ไม่ต้องส่งผ่าน Header → Nav
  const { isDark, setIsDark } = useContext(ThemeContext);
  const { language } = useContext(LanguageContext);

  const labels = {
    th: { light: "โหมดสว่าง", dark: "โหมดมืด" },
    en: { light: "Light Mode", dark: "Dark Mode" },
  };

  return (
    <button
      onClick={() => setIsDark(!isDark)}
      style={{ color: isDark ? "white" : "black" }}
    >
      {isDark ? labels[language].light : labels[language].dark}
    </button>
  );
}
```

**เปรียบเทียบ:**

| ด้าน                | Props Drilling               | useContext           |
| ------------------- | ---------------------------- | -------------------- |
| Component ระดับกลาง | ต้องรับ props ที่ไม่ใช้      | ไม่ต้องรับ props เลย |
| Code ชัดเจน         | ซ้อนลึก                      | ดูเหมือนเรียบง่าย    |
| Maintainability     | ยากเปลี่ยน                   | ง่ายเปลี่ยน          |
| ใหญ่ขึ้น            | Props เพิ่ม → ต้องส่งทั้งหมด | ไม่ส่งผ่าน → ดึงตรงๆ |

### เมื่อไหร่ควรใช้ useContext?

**ใช้ useContext เมื่อ:**

- ข้อมูล global ที่ใช้ทั่วแอป (Theme, Language, Authentication)
- Props ต้องผ่านมากกว่า 2-3 level
- หลีกเลี่ยง Props Drilling ที่ทำให้ Component ยุ่ง

**ไม่ควรใช้ useContext เมื่อ:**

- ข้อมูล local ของ Component (ใช้ useState ของตัวเอง)
- State ซับซ้อนและเปลี่ยนบ่อย > 3 ครั้ง/วินาที (ใช้ Redux หรือ Zustand)
- เชื่อมกับ API หลายจุด (ใช้ React Query หรือ SWR)

### ตัวอย่าง: Dark Mode Theme

#### ขั้นตอน 1: สร้าง Context

```javascript
// src/ThemeContext.jsx
import { createContext, useState } from "react";

export const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [isDark, setIsDark] = useState(false);

  function toggleTheme() {
    setIsDark(!isDark);
  }

  return (
    <ThemeContext.Provider value={{ isDark, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}
```

#### ขั้นตอน 2: ใช้ Provider ใน main.jsx

```javascript
// src/main.jsx
import { ThemeProvider } from "./ThemeContext";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")).render(
  <ThemeProvider>
    <App />
  </ThemeProvider>,
);
```

#### ขั้นตอน 3: ใช้ useContext ใน Component

```javascript
// src/App.jsx
import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

export default function App() {
  const { isDark, toggleTheme } = useContext(ThemeContext);

  return (
    <div
      style={{
        backgroundColor: isDark ? "#333" : "#fff",
        color: isDark ? "#fff" : "#000",
        minHeight: "100vh",
        padding: "20px",
      }}
    >
      <h1>Dark Mode Example</h1>
      <button onClick={toggleTheme}>
        {isDark ? "Light Mode" : "Dark Mode"}
      </button>
    </div>
  );
}
```

### ตัวอย่าง: Authentication Context

```javascript
// src/AuthContext.jsx
import { createContext, useState } from 'react'

export const AuthContext = createContext()

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null)

  function login(username) {
    setUser({ name: username, id: 1 })
  }

  function logout() {
    setUser(null)
  }

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  )
}

// src/Pages/Login.jsx
import { useContext } from 'react'
import { AuthContext } from '../AuthContext'

export default function Login() {
  const { login } = useContext(AuthContext)

  function handleLogin() {
    login('สมชาย')
  }

  return (
    <div style={{ padding: '20px' }}>
      <button onClick={handleLogin}>เข้าสู่ระบบ</button>
    </div>
  )
}

// src/Components/UserProfile.jsx
import { useContext } from 'react'
import { AuthContext } from '../AuthContext'

export default function UserProfile() {
  const { user, logout } = useContext(AuthContext)

  if (!user) return <p>ยังไม่เข้าสู่ระบบ</p>

  return (
    <div>
      <h2>{user.name}</h2>
      <button onClick={logout}>ออกจากระบบ</button>
    </div>
  )
}
```

### Nested Context - เมื่อมี Context หลายตัว

ในแอปจริง มักมีหลาย Context (Theme, Auth, Language, etc.) ต้องห่อกัน:

```javascript
// src/main.jsx
import { ThemeProvider } from "./ThemeContext";
import { AuthProvider } from "./AuthContext";
import { LanguageProvider } from "./LanguageContext";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")).render(
  <ThemeProvider>
    <AuthProvider>
      <LanguageProvider>
        <App />
      </LanguageProvider>
    </AuthProvider>
  </ThemeProvider>,
);
```

ทีนี้ Component ใดๆ ก็ได้สามารถใช้ได้:

```javascript
function Header() {
  const { isDark, toggleTheme } = useContext(ThemeContext);
  const { user } = useContext(AuthContext);
  const { language, setLanguage } = useContext(LanguageContext);

  // ใช้ได้หมด
}
```

### Performance - useMemo สำหรับ Context Value

**ปัญหา:** ถ้า Context value เป็น object ใหม่ทุกครั้งที่ render จะทำให้ Component ที่ใช้ Context re-render ไม่จำเป็น

```javascript
// ❌ ผิด - value สร้างใหม่ทุกครั้ง
export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);

  return (
    <AuthContext.Provider value={{ user, setUser }}>
      {/* ทุกครั้ง render: value = object ใหม่ → child components re-render */}
      {children}
    </AuthContext.Provider>
  );
}

// ✅ ถูกต้อง - ใช้ useMemo เพื่อ memoize value
import { useMemo } from "react";

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);

  const value = useMemo(() => ({ user, setUser }), [user]);

  return (
    <AuthContext.Provider value={value}>
      {/* value เปลี่ยนแค่เมื่อ user เปลี่ยน */}
      {children}
    </AuthContext.Provider>
  );
}
```

### สิ่งที่ทำผิดบ่อย (useContext)

#### 1. ลืม `export` Context

```javascript
// ❌ ผิด - Context ไม่ได้ export
const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [isDark, setIsDark] = useState(false);

  return (
    <ThemeContext.Provider value={{ isDark }}>{children}</ThemeContext.Provider>
  );
}

// ในไฟล์อื่น: ใช้ไม่ได้!
// import { ThemeContext } from "./ThemeContext" ← ไม่มี export

// ✅ ถูกต้อง
export const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  // ...
}
```

#### 2. ลืม `<Provider>` Wrapper

```javascript
// ❌ ผิด - ไม่มี Provider ห่อ App
ReactDOM.createRoot(root).render(<App />);

// Component ที่ใช้ useContext จะ error:
// "useContext(ThemeContext) may be used only within ThemeProvider"

// ✅ ถูกต้อง - ต้องห่อด้วย Provider ในขั้นบน
ReactDOM.createRoot(root).render(
  <ThemeProvider>
    <App />
  </ThemeProvider>,
);
```

#### 3. ไม่ส่ง `value` prop ใน Provider

```javascript
// ❌ ผิด - ไม่มี value
export function ThemeProvider({ children }) {
  const [isDark, setIsDark] = useState(false);

  return (
    <ThemeContext.Provider>
      {/* ไม่มี value → useContext ได้ undefined */}
      {children}
    </ThemeContext.Provider>
  );
}

// ✅ ถูกต้อง - ต้องส่ง value
return (
  <ThemeContext.Provider value={{ isDark, setIsDark }}>
    {children}
  </ThemeContext.Provider>
);
```

#### 4. ลืม `useContext()` Hook

```javascript
// ❌ ผิด - เข้าถึง Context โดยตรง
import { ThemeContext } from "./ThemeContext";

function Button() {
  // ไม่สามารถใช้ Context value ได้
  const isDark = ThemeContext.isDark; // ❌ undefined!
}

// ✅ ถูกต้อง - ต้องใช้ useContext hook
import { useContext } from "react";

function Button() {
  const { isDark } = useContext(ThemeContext);
  // ✅ ได้ค่าจาก value
}
```

#### 5. Context Value เปลี่ยนทำให้ Child Re-render เยอะ

```javascript
// ❌ ผิด - object ใหม่ทุกครั้ง
export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);

  return (
    <AuthContext.Provider value={{ user, setUser }}>
      {/* ทุก render: value object ใหม่ → ทำให้ 1000 child components re-render */}
      {children}
    </AuthContext.Provider>
  );
}

// ✅ ถูกต้อง - ใช้ useMemo
const value = useMemo(() => ({ user, setUser }), [user]);

return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
```

---

## 3. Deployment - ส่งแอปไปออนไลน์

### Deployment คืออะไร?

บทนี้จะนำเสนอวิธีส่ง React แอปไปยังโฮสติง Cloud เช่น Vercel หรือ Netlify ด้วยการตั้งค่า Environment Variables และ Deployment Pipeline เพื่อให้ใช้งานได้จริง

### การ Deploy ไป Vercel

#### ขั้นตอนที่ 1: สร้างบัญชี Vercel

1. ไปที่ https://vercel.com
2. Sign up ด้วย GitHub account
3. Authorize Vercel

#### ขั้นตอนที่ 2: Deploy โครงการ

```bash
git add .
git commit -m "Ready to deploy"
git push origin main
```

จากนั้นไปที่ Vercel Dashboard และทำตามขั้นตอนเพิ่มเติม

#### ขั้นตอนที่ 3: ตั้งค่า (ถ้าจำเป็น)

```
Framework Preset: Vite
Build Command: npm run build
Output Directory: dist
Environment Variables: (ถ้าจำเป็น)
```

**ผลลัพธ์:** URL จะเป็นแบบนี้

```
https://my-app.vercel.app
```

### การ Deploy ไป Netlify

#### ขั้นตอนที่ 1: Build โครงการ

```bash
npm run build
```

**ผลลัพธ์:** โฟลเดอร์ `dist/` จะถูกสร้าง

#### ขั้นตอนที่ 2: Upload ไป Netlify

```bash
npm install -g netlify-cli
netlify deploy
```

#### หรือ Deploy ผ่าน Git

1. ไปที่ https://netlify.com
2. Sign up ด้วย GitHub
3. Click "New site from Git"
4. Select repository
5. Configure build settings:
   ```
   Build command: npm run build
   Publish directory: dist
   ```
6. Click "Deploy site"

**ผลลัพธ์:** URL จะเป็นแบบนี้

```
https://my-app.netlify.app
```

### Checklist ก่อน Deploy

- ทดสอบใน production: `npm run build && npm run preview`
- แก้ไขปัญหา (console errors)
- เปลี่ยน API endpoints เป็น production
- ตรวจสอบ environment variables
- ทดสอบบน mobile

### Security - API Keys & Secrets

**เตือน: ห้ามใส่ API key ใน Source Code!**

**วิธีถูกต้อง:**

```javascript
// ❌ ผิด - API key เห็นได้เลย
const API_KEY = "sk-abc123xyz";
const response = await fetch(`https://api.example.com?key=${API_KEY}`);

// ✅ ถูกต้อง - ใช้ Environment Variables
const API_KEY = import.meta.env.VITE_API_KEY;
const response = await fetch(`https://api.example.com?key=${API_KEY}`);
```

**ตั้งค่า Environment Variables:**

1. **สร้างไฟล์ `.env.local` (จะถูก git ignore)**

   ```
   VITE_API_KEY=sk-1234567890abcdef
   VITE_API_URL=https://api.example.com
   ```

2. **ใน code ใช้:**

   ```javascript
   const apiKey = import.meta.env.VITE_API_KEY;
   const apiUrl = import.meta.env.VITE_API_URL;
   ```

3. **ใน Vercel/Netlify Dashboard ตั้งค่า:**
   - Vercel: Project Settings → Environment Variables
   - Netlify: Site settings → Build & Deploy → Environment

**ตัวอย่าง Vercel Environment Variables:**

```
VITE_API_KEY = sk-prod-xxxxxxxxxxxxx
VITE_API_URL = https://api-prod.example.com
```

---

## ตัวอย่าง: Multi-page React App

สร้างเว็บแอปพลิเคชัน React ที่มี:

- หน้าแรก (Home)
- หน้าเกี่ยวกับ (About)
- หน้าติดต่อ (Contact)
- หน้ารายละเอียด (Detail)

### โครงสร้าง

```
src/
├── App.jsx
├── main.jsx
├── pages/
│   ├── Home.jsx
│   ├── About.jsx
│   ├── Contact.jsx
│   └── UserDetail.jsx
├── components/
│   └── Navigation.jsx
└── context/
    └── ThemeContext.jsx
```

### ตัวอย่าง: App.jsx

```javascript
import { Routes, Route } from "react-router-dom";
import Navigation from "./components/Navigation";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";
import UserDetail from "./pages/UserDetail";

export default function App() {
  return (
    <div>
      <Navigation />

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
        <Route path="/user/:id" element={<UserDetail />} />
      </Routes>
    </div>
  );
}
```

### ตัวอย่าง: Navigation.jsx

```javascript
import { Link } from "react-router-dom";

export default function Navigation() {
  return (
    <nav
      style={{
        backgroundColor: "#007bff",
        padding: "20px",
        display: "flex",
        gap: "20px",
      }}
    >
      <Link to="/" style={{ color: "white", textDecoration: "none" }}>
        Home
      </Link>
      <Link to="/about" style={{ color: "white", textDecoration: "none" }}>
        About
      </Link>
      <Link to="/contact" style={{ color: "white", textDecoration: "none" }}>
        Contact
      </Link>
    </nav>
  );
}
```

### ตัวอย่าง: Home.jsx

```javascript
import { Link } from "react-router-dom";

export default function Home() {
  const users = [
    { id: 1, name: "สมชาย" },
    { id: 2, name: "สมหญิง" },
  ];

  return (
    <div style={{ padding: "20px", maxWidth: "900px", margin: "0 auto" }}>
      <h1>หน้าแรก</h1>
      <p>ยินดีต้อนรับเข้าสู่เว็บไซต์ของเรา</p>

      <h2>ผู้ใช้</h2>
      <div style={{ display: "flex", gap: "20px", flexWrap: "wrap" }}>
        {users.map((user) => (
          <div
            key={user.id}
            style={{
              border: "1px solid #ddd",
              padding: "20px",
              borderRadius: "8px",
              minWidth: "200px",
            }}
          >
            <h3>{user.name}</h3>
            <Link to={`/user/${user.id}`}>ดูรายละเอียด</Link>
          </div>
        ))}
      </div>
    </div>
  );
}
```

### ตัวอย่าง: UserDetail.jsx

```javascript
import { useParams, Link } from "react-router-dom";

export default function UserDetail() {
  const { id } = useParams();

  const users = {
    1: {
      name: "สมชาย",
      email: "somchai@example.com",
      role: "นักพัฒนา",
    },
    2: {
      name: "สมหญิง",
      email: "somying@example.com",
      role: "ผู้ออกแบบ",
    },
  };

  const user = users[id];

  if (!user) {
    return <div style={{ padding: "20px" }}>ไม่พบผู้ใช้</div>;
  }

  return (
    <div style={{ padding: "20px", maxWidth: "600px", margin: "0 auto" }}>
      <Link to="/">กลับไปหน้าแรก</Link>

      <div
        style={{
          border: "1px solid #ddd",
          padding: "20px",
          borderRadius: "8px",
          marginTop: "20px",
        }}
      >
        <h2>{user.name}</h2>
        <p>
          <strong>Email:</strong> {user.email}
        </p>
        <p>
          <strong>ตำแหน่ง:</strong> {user.role}
        </p>
      </div>
    </div>
  );
}
```

---

## สรุปสัปดาห์ที่ 14

| หัวข้อ         | สิ่งที่เรียนรู้                |
| -------------- | ------------------------------ |
| **Router**     | สร้างหลายหน้า ด้วย URL routing |
| **useContext** | แชร์ State ระหว่าง Components  |
| **Deployment** | ส่ง React แอป ไปออนไลน์        |

---

## บ่อยทำผิด (Common Mistakes)

### 1. ลืม `<BrowserRouter>` Wrapper

```javascript
// ❌ ผิด - ใช้ Routes โดยไม่มี BrowserRouter
import App from "./App";
ReactDOM.render(<App />, root);

// ✅ ถูกต้อง - ต้องใส่ BrowserRouter
import { BrowserRouter } from "react-router-dom";

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  root,
);
```

**ผลลัพธ์ถ้าลืม:** Error "useNavigate() may be used only within a <Router> component."

### 2. ใช้ `<a>` แทน `<Link>`

```javascript
// ❌ ผิด - reload หน้า + สูญเสีย state
<a href="/about">เกี่ยวกับ</a>

// ✅ ถูกต้อง - ไม่ reload + เก็บ state
<Link to="/about">เกี่ยวกับ</Link>
```

### 3. Path ไม่ตรง

```javascript
// ❌ ผิด - path ไม่ตรง URL
<Route path="/user" element={<UserList />} />
// ต้องจะไป /users ถึงจะแสดง

// ✅ ถูกต้อง
<Route path="/users" element={<UserList />} />
<Route path="/user/:id" element={<UserDetail />} />
```

### 4. ลืม `export` Context

```javascript
// ❌ ผิด - ไม่ export ThemeContext
export function ThemeProvider({ children }) {
  return <ThemeContext.Provider value={...}>{children}</ThemeContext.Provider>
}

// ✅ ถูกต้อง
export const ThemeContext = createContext()
export function ThemeProvider({ children }) {
  return <ThemeContext.Provider value={...}>{children}</ThemeContext.Provider>
}
```

### 5. Deploy แต่ไม่ build

```bash
# ❌ ผิด - push source code โดยไม่ build
git push origin main
# Vercel/Netlify ต้องรัน build เอง

# ✅ ถูกต้อง - ให้ CI/CD build โดยอัตโนมัติ
# หรือ build ก่อน deploy
npm run build
```

### 6. ไม่ใช้ `useNavigate()` สำหรับ Redirect

```javascript
// ❌ ผิด - ใช้ history API โดยตรง (ไม่ work ใน React Router v6)
window.location.href = "/home";

// ✅ ถูกต้อง
const navigate = useNavigate();
navigate("/home");
```

---

## Deployment - Troubleshooting

### ปัญหา: Build Success แต่หน้าแสดง 404

**สาเหตุ:** Vercel/Netlify ไม่รู้ว่า Single Page App ต้องให้ index.html

**วิธีแก้:**

1. **Vercel** - ตั้งค่า auto แล้ว (ปกติไม่มีปัญหา)
2. **Netlify** - สร้างไฟล์ `netlify.toml`:
   ```toml
   [[redirects]]
   from = "/*"
   to = "/index.html"
   status = 200
   ```

### ปัญหา: API Key โปรดายลาน

**ต้องหลีกเลี่ยง:**

```javascript
// ❌ ผิด - API key อยู่ใน code
const API_KEY = "sk-1234567890abcdef";
fetch(`https://api.example.com?key=${API_KEY}`);
```

**วิธีแก้:**

```javascript
// ✅ ถูกต้อง - ใช้ Environment Variables
const API_KEY = import.meta.env.VITE_API_KEY;
fetch(`https://api.example.com?key=${API_KEY}`);
```

ตั้งค่าใน Vercel/Netlify Dashboard:

- Environment Variables → เพิ่ม `VITE_API_KEY=sk-xxxxx`

### วิธีดู Logs

**Vercel:**

- เข้า Dashboard → Project → Deployments → คลิก Deploy ที่ล่มสุด → ดู Logs

**Netlify:**

- เข้า Site → Deploy → คลิก Deploy ที่ล่มสุด → ดู logs

---

## Practice Exercises

### Exercise 1: สร้าง Blog App (45 นาที)

**เกี่ยวข้องกับ:** React Router basics

สร้างเว็บ Blog ที่มี:

- หน้า Home - แสดง Article List
- หน้า Article Detail - `/:articleId`
- ใช้ `useParams()` ดึง ID จาก URL
- ใช้ `<Link>` navigate ไปยัง article

**Starter code:**

```javascript
const articles = [
  { id: 1, title: "React 101", content: "..." },
  { id: 2, title: "React Router", content: "..." },
];
```

### Exercise 2: Dark Mode Toggle (30 นาที)

**เกี่ยวข้องกับ:** useContext

สร้าง Dark Mode:

- สร้าง ThemeContext
- สร้าง ThemeProvider
- เพิ่ม Toggle button ที่เปลี่ยน theme
- ให้ทุก component ใช้ theme จาก Context

### Exercise 3: E-commerce Filter (1 ชั่วโมง)

**เกี่ยวข้องกับ:** useSearchParams + useContext

สร้างหน้าร้านค้า:

- Filter ตามหมวดหมู่ (query string)
- Sort ตามราคา (query string)
- Pagination ด้วย query string
- Add to Cart (State ใน Context)

### Exercise 4: Deploy ไปออนไลน์ (30 นาที)

**เกี่ยวข้องกับ:** Deployment

Take any project ที่สร้างแล้ว:

- Push ไป GitHub
- Deploy ไป Vercel หรือ Netlify
- ทดสอบ routing บนมือถือ
- ตรวจสอบ console errors

---

## ขั้นตอนถัดไป

1. ฝึกสร้าง Components ต่างๆ มากขึ้น
2. สร้าง Project แบบจริง (To-Do App, Blog, etc)
3. เรียนรู้ State Management ขั้นสูง (Redux, Zustand)
4. API Integration กับ backend ของจริง
5. Testing Components ด้วย Jest/React Testing Library

---

## Resources

- [React Official Docs](https://react.dev)
- [React Router Docs](https://reactrouter.com)
- [Vercel Docs](https://vercel.com/docs)
- [Netlify Docs](https://docs.netlify.com)

---
