การสร้าง UI ด้วย React (I) - การสร้าง React Component
Tags: webdev, react, beginners
Published: 2024-02-26 15:01:32

เนืองจากมีหลายคนที่มาให้สอน React แต่เนื่องด้วยสอนแล้วมันไม่มีที่ที่จะเก็บเป็นหลักแหล่ง เลยจะมาเขียนเป็นโพสซีรี่ย์ตอนยาว โดยอ้างอิงจาก react.dev ในส่วนของ [Learn React](https://react.dev/learn) แม้เอกสารจะอธิบายอย่างละเอียดแล้ว แต่เป็นภาษาอังกฤษ จึงขอแปลภาษาไทย ในภาษาของเราเอง และย่อเนื้อหาไม่ให้ยืดมาก

## การสร้าง UI ด้วย React

React เป็น Library สำหรับการสร้าง UI เพื่อนำส่วนต่างๆ ไปใช้ซ้ำ ในบทนี้เราจะเรียนรู้วิธีสร้าง, ปรับแต่ง และ การแสดง UI แบบมีเงื่อนไข ของ React Component

---

ในซีรีย์นี้:
- **การสร้าง React Component**
- [Import และ Export Component](https://dev.to/21aki/kaarsraang-ui-dwy-react-ii-import-aela-export-component-pge)
- [เขียน JSX](https://dev.to/21aki/kaarsraang-ui-dwy-react-iii-kaarekhiiyn-jsx-484h)
- ใช้ ปีกกา ใน JSX
- ส่งค่าผ่าน Props
- การแสดง Component แบบมีเงื่อนไข (Conditional Rendering)
- การแสดงข้อมูลเป็น List
- แยก Component (สร้าง Pure Component)
- มอง UI ให้เป็นแผนภูมิต้นไม้ (Tree Structure)

---

## การสร้าง React Component
การเขียน React เป็นการสร้าง UI ส่วนย่อยๆ เรียกว่า Components, เขียนเป็นฟังก์ชั่น JavaScript ที่สามารถใช้ HTML ได้

### Components: คือการประกอบร่าง UI

ใน HTML เราสามารถสร้างหน้าตาเว็บด้วยแท็กต่างๆ เช่น `<h1>` และ `<li>`:

```html
<article>
  <h1>My First Component</h1>
  <ol>
    <li>Components: UI Building Blocks</li>
    <li>Defining a Component</li>
    <li>Using a Component</li>
  </ol>
</article>
```

React จะช่วยในการรวม HTML, CSS และ JavaScript เป็น Component และนำไปใช้ซ้ำได้ 

การใช้ Component ของ React เหมือนการใช้แท็กของ HTML เช่นเมื่อรวมโค้ด HTML ด้านบนเป็น Component ชื่อว่า `<TableOfContents /> ` สามารถนำ Component นี้ไปใช้ซ้ำที่ไหนได้ ดังตัวอย่าง:

```jsx
<PageLayout>
  <NavigationHeader>
    <SearchBar />
    <Link to="/docs">Docs</Link>
  </NavigationHeader>
  <Sidebar />
  <PageContent>
    <TableOfContents />
    <DocumentationText />
  </PageContent>
</PageLayout>
```

### การประกาศ Component

ปกติการสร้างเว็บ เราจะเขียน HTML ก่อนแล้วใส่ JavaScript ไปกำกับ แต่ React จะเปลี่ยนเป็น เขียนฟังค์ชั่น JavaScript เพื่อแสดง HTML แทน (ดังตัวอย่างข้างล่าง):

{% codesandbox react-dev-c269cw %}

### Step 1: Export ตัว Component

ใช้คำสั่ง JavaScript `export default` ในการประกาศฟังค์ชั่นหลักของไฟล์ เพื่อใช้ในการนำฟังค์ชั่นไปใช้ในไฟล์อื่นในภายหลัง

### Step 2: ตั้งชื่อฟังค์ชั่น

ใช้ `function Profile() { }` เพื่อสร้างฟังค์ชั่น JavaScript ชื่อ `Profile`

> **⚠️ ผิดกันง่ายๆ**
> Component ของ React ก็คือฟังค์ชั่น JavaScript แต่จะ<u>ต้องตั้งชื่อ ด้วยตัวพิมพ์ใหญ่นำหน้าเสมอ</u>

### Step 3: ใส่ HTML เวอร์ชั่น JavaScript

จากนั้นเราจะ return แท็ก `<img />`แต่จะต้องเป็นเวอร์ชั่นของ JavaScript ที่เรีกว่า JSX

ถ้าเราจะ return บรรทัดเดียว:

```jsx
return <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />;
```

ถ้าจะ return หลายบรรทัด ให้ใส่วงเล็บครอบ:

```jsx
return (
  <div>
    <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
  </div>
);
```

> **⚠️ ผิดกันง่ายๆ**
> ถ้าไม่ครอบวงเล็บ โค้ดบรรทัดอื่นๆ หลัง `return` จะไม่ถูกใช้งาน

### ใช้ Component

เมื่อเราสร้าง Component `Profile` แล้ว สามารถเอามันไปใช้ใน Component อื่นๆ ได้ เช่นเราจะสร้าง Component `Gallery` ทีใช้ Component `Profile` หลายอันข้างใน

{% codesandbox react-dev-xgy8t9 %}

### สิ่งที่ Browser แสดง

เมื่อ Browser นำไปแสดง จะถูกแปลงเป็น HTML ปกติ:

```html
<section>
  <h1>Amazing scientists</h1>
  <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
  <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
  <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
</section>
```

### การซ้อน และ การจัดการ Components

Component เป็นฟังค์ชั่น JavaScript ธรรมดา ฉนั้น เราจะเขียน Component ไว้ในไฟล์เดียวกันได้ แต่ถ้าโค้ดของ Component เริ่มเยอะการแบ่ง 1 Component ต่อ 1 ไฟล์ จะทำให้จัดการง่ายกว่า

จากโค้ดที่ผ่านมา จะเห็นว่าเราใช้ Component `Profile` หลายๆ อันใน Component `Gallery` เราจะเรียกความสัมพันธ์แบบนี้ว่า `Gallery` เป็น Component แม่ (parent) และ `Profile` เป็น Component ลูก (child)

> **⚠️ ผิดกันง่ายๆ**
> Component สามารถ render อีก Component ได้ แต่ไม่ควรประกาศซ้อนไว้ในอีก Component: 
> 
> ```jsx
> export default function Gallery() {
>   // 🔴 อย่าประกาศอีก Component ข้างใน Component แบบนี้!
>   function Profile() {
>     // ...
>   }
>   // ...
> }
> ```
> 
> แบบนี้ Bug จะเยอะและทำให้ช้า ทางที่ดีความประกาศแยกในชั้นบนสุด
> 
> ```jsx
> export default function Gallery() {
>   // ...
> }
> 
> // ✅ ประกาศ Component ในชั้นบนสุด
> function Profile() {
>   // ...
> }
> ```
> 
> หาก Component ลูกต้องการข้อมูลจากแม่ ให้ส่งผ่าน Props แทนการประการฟังค์ชั่นซ้อน

## สรุป

- React ทำให้เราสร้าง Component หรือ UI ที่สามารถใช้ซ้ำได้
- ใน React ทุกส่วนย่อยๆ ของ UI เรียกว่า Component
- Component ของ React เป็นฟังค์ชั่น JavaScript ธรรมดา แต่:
    1. ต้องตั้งชื่อขึ้นต้นด้วยตัวพิมพ์ใหญ่
    2. ต้อง return ด้วย JSX