สอน React ตั้งแต่ต้น สร้างเว็บด้วยตัวอย่าง 21 เรื่อง
React คือไลบรารี JavaScript สำหรับสร้างหน้าเว็บแบบโต้ตอบได้ โดยแบ่งหน้าเว็บออกเป็นชิ้นย่อยๆ ที่เรียกว่า component แต่ละชิ้นรับข้อมูลเข้ามา แล้วคืนค่าเป็นส่วนของหน้าเว็บ บทความนี้พาคุณไปจากการแสดงข้อความแรก ไปจนถึงการประกอบหน้าเว็บเล็กๆ ที่มีเมนู การ์ดจากข้อมูล และส่วนท้ายเว็บ ทุกตัวอย่างเป็นไฟล์จริงที่รันแล้ว และผลลัพธ์ที่แสดงคือผลที่ได้จากการรันจริง
สิ่งที่ต้องเตรียม
ต้องมี Node.js เวอร์ชัน 18 ขึ้นไป พื้นฐาน JavaScript และ editor ใดก็ได้ ติดตั้งแพ็กเกจด้วยคำสั่ง npm install [email protected] [email protected] แล้วรันแต่ละตัวอย่างด้วยตัวทดสอบของบทความนี้ ตัวอย่างที่มี steps จะจำลองการคลิกปุ่มในเบราว์เซอร์เสมือนด้วย jsdom
ภาพประกอบ
ตัวอย่างที่ 1: แสดงข้อความแรก
component คือฟังก์ชันที่คืนค่า JSX ตัวอย่างนี้สร้างหัวข้อแรกและแปลงเป็น HTML ด้วย renderToStaticMarkup
import React from "react";
export function App() {
return <h1>สวัสดี React</h1>;
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<h1>สวัสดี React</h1>
ตัวอย่างที่ 2: แสดงรายการด้วย map
ใช้ map แปลงอาร์เรย์เป็นรายการ li ทุกตัว ข้อมูลเปลี่ยนแล้วหน้าเว็บตามไปด้วยโดยไม่ต้องแก้ HTML
import React from "react";
const fruits = ["ทุเรียน", "มังคุด", "มะม่วง"];
export function App() {
return (
<ul>
{fruits.map(f => <li key={f}>{f}</li>)}
</ul>
);
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<ul><li>ทุเรียน</li><li>มังคุด</li><li>มะม่วง</li></ul>
ตัวอย่างที่ 3: ส่ง props ให้ component
props คือข้อมูลที่ component แม่ส่งให้ลูก component เดียวกันใช้ซ้ำได้กับข้อมูลต่างกัน
import React from "react";
function Greeting({ name, age }) {
return <p>สวัสดี {name} อายุ {age} ปี</p>;
}
export function App() {
return (
<div>
<Greeting name="สมชาย" age={20} />
<Greeting name="สมหญิง" age={22} />
</div>
);
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<div><p>สวัสดี สมชาย อายุ 20 ปี</p><p>สวัสดี สมหญิง อายุ 22 ปี</p></div>
ตัวอย่างที่ 4: แสดงผลตามเงื่อนไข
ใช้ && และ ternary เพื่อเลือกว่าจะแสดงอะไรในหน้าเว็บ
import React from "react";
function Status({ online }) {
return (
<div>
{online ? <span>ออนไลน์</span> : <span>ออฟไลน์</span>}
{online && <em>พร้อมแชท</em>}
</div>
);
}
export function App() {
return <Status online={true} />;
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<div><span>ออนไลน์</span><em>พร้อมแชท</em></div>
ตัวอย่างที่ 5: Fragment
เมื่อไม่ต้องการ div ครอบ ให้ใช้ <> ... </> ครอบ element หลายตัวไว้ด้วยกัน
import React from "react";
function Header() {
return (
<>
<h2>หัวข้อ</h2>
<p>ไม่ต้องครอบด้วย div</p>
</>
);
}
export function App() {
return <Header />;
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<h2>หัวข้อ</h2><p>ไม่ต้องครอบด้วย div</p>
ตัวอย่างที่ 6: key ในตาราง
สร้างตารางจากข้อมูลและใช้ id เป็น key ให้ React ระบุแถวแต่ละแถวได้
import React from "react";
const students = [
{ id: 1, name: "สมชาย", score: 85 },
{ id: 2, name: "สมหญิง", score: 72 },
];
export function App() {
return (
<table>
<tbody>
{students.map(s => (
<tr key={s.id}>
<td>{s.name}</td>
<td>{s.score}</td>
</tr>
))}
</tbody>
</table>
);
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<table><tbody><tr><td>สมชาย</td><td>85</td></tr><tr><td>สมหญิง</td><td>72</td></tr></tbody></table>
ตัวอย่างที่ 7: style เป็น object
style ใน React รับ object และใช้ camelCase เช่น backgroundColor และ borderRadius
import React from "react";
const box = {
padding: 12,
backgroundColor: "#eef4ff",
borderRadius: 8,
color: "#1a1a1a",
};
export function App() {
return <div style={box}>กล่องที่ตกแต่งด้วย style object</div>;
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<div style="padding:12px;background-color:#eef4ff;border-radius:8px;color:#1a1a1a">กล่องที่ตกแต่งด้วย style object</div>
ตัวอย่างที่ 8: children
ส่ง JSX เข้าไประหว่างแท็กเปิดกับแท็กปิด เพื่อให้ component ห่อเนื้อหาใดก็ได้
import React from "react";
function Card({ title, children }) {
return (
<section>
<h3>{title}</h3>
<div>{children}</div>
</section>
);
}
export function App() {
return (
<Card title="ข่าวสาร">
<p>เนื้อหาที่ส่งเข้าไปใน children</p>
</Card>
);
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<section><h3>ข่าวสาร</h3><div><p>เนื้อหาที่ส่งเข้าไปใน children</p></div></section>
ตัวอย่างที่ 9: state ตัวนับ
useState เก็บค่าที่เปลี่ยนได้ เมื่อเรียก setter React จะ render ใหม่ ตัวอย่างนี้คลิกปุ่มสองครั้งแล้วดูค่าเปลี่ยน
import React, { useState } from "react";
export function App() {
const [count, setCount] = useState(0);
return (
<div>
<p data-out>นับ: {count}</p>
<button id="inc" onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
export const steps = ["#inc", "#inc"];
**ผลลัพธ์ที่ได้จากการรันจริง**
ข้อความเริ่มต้น: นับ: 0
หลังคลิกครั้งที่ 1: นับ: 1
หลังคลิกครั้งที่ 2: นับ: 2
ตัวอย่างที่ 10: input แบบ controlled
ค่าของ input ถูกควบคุมด้วย state ทุกการพิมพ์ผ่าน onChange ตัวอย่างนี้แสดงค่าเริ่มต้นเป็นศูนย์ตัวอักษร
import React, { useState } from "react";
export function App() {
const [text, setText] = useState("");
return (
<div>
<input id="box" value={text} onChange={e => setText(e.target.value)} />
<p>พิมพ์แล้ว: {text.length} ตัวอักษร</p>
</div>
);
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<div><input id="box" value=""/><p>พิมพ์แล้ว: 0 ตัวอักษร</p></div>
ตัวอย่างที่ 11: สวิตช์เปิดปิด
เก็บค่า boolean ใน state แล้วสลับค่าด้วย !on ทุกครั้งที่คลิก
import React, { useState } from "react";
export function App() {
const [on, setOn] = useState(false);
return (
<div>
<p data-out>{on ? "เปิดอยู่" : "ปิดอยู่"}</p>
<button id="toggle" onClick={() => setOn(!on)}>สลับ</button>
</div>
);
}
export const steps = ["#toggle", "#toggle"];
**ผลลัพธ์ที่ได้จากการรันจริง**
ข้อความเริ่มต้น: ปิดอยู่
หลังคลิกครั้งที่ 1: เปิดอยู่
หลังคลิกครั้งที่ 2: ปิดอยู่
ตัวอย่างที่ 12: useEffect
effect ทำงานหลังจาก render เสร็จ ใช้กับงานอย่างการโหลดข้อมูลหรือตั้งค่าเมื่อ component ถูกแสดงครั้งแรก
import React, { useEffect, useState } from "react";
export function App() {
const [message, setMessage] = useState("กำลังโหลด");
useEffect(() => {
setMessage("โหลดเสร็จแล้ว (จาก useEffect)");
}, []);
return <p data-out>{message}</p>;
}
export const steps = [];
**ผลลัพธ์ที่ได้จากการรันจริง**
ข้อความเริ่มต้น: โหลดเสร็จแล้ว (จาก useEffect)
ตัวอย่างที่ 13: ฟอร์มบันทึกค่า
อ่านค่าจาก input เก็บใน state แล้วบันทึกเมื่อกดปุ่ม ตัวอย่างนี้ตั้งชื่อเริ่มต้นเป็นสมชาย
import React, { useState } from "react";
export function App() {
const [name, setName] = useState("สมชาย");
const [saved, setSaved] = useState("");
return (
<div>
<input value={name} onChange={e => setName(e.target.value)} />
<button id="save" onClick={() => setSaved(name)}>บันทึก</button>
<p data-out>บันทึกแล้ว: {saved || "ยังไม่มี"}</p>
</div>
);
}
export const steps = ["#save"];
**ผลลัพธ์ที่ได้จากการรันจริง**
ข้อความเริ่มต้น: บันทึกแล้ว: ยังไม่มี
หลังคลิกครั้งที่ 1: บันทึกแล้ว: สมชาย
ตัวอย่างที่ 14: รายการงาน
เพิ่มรายการใหม่โดยสร้าง array ใหม่ด้วย spread แทนการแก้ array เดิม
import React, { useState } from "react";
let nextId = 1;
export function App() {
const [items, setItems] = useState([]);
const add = () => {
const id = nextId++;
setItems([...items, { id, text: "งานที่ " + id }]);
};
return (
<div>
<button id="add" onClick={add}>เพิ่มงาน</button>
<ul data-out>{items.map(i => <li key={i.id}>{i.text}</li>)}</ul>
</div>
);
}
export const steps = ["#add", "#add"];
**ผลลัพธ์ที่ได้จากการรันจริง**
ข้อความเริ่มต้น:
หลังคลิกครั้งที่ 1: งานที่ 1
หลังคลิกครั้งที่ 2: งานที่ 1งานที่ 2
ตัวอย่างที่ 15: Context
ส่งค่าธีมลงไปถึง component ลึกๆ โดยไม่ต้องส่ง props ผ่านทุกชั้น
import React, { createContext, useContext } from "react";
const ThemeContext = createContext("light");
function Button() {
const theme = useContext(ThemeContext);
return <button>ธีม: {theme}</button>;
}
export function App() {
return (
<ThemeContext.Provider value="dark">
<Button />
</ThemeContext.Provider>
);
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<button>ธีม: dark</button>
ตัวอย่างที่ 16: useReducer
จัดการ state ที่มีหลายค่าหรือหลายการกระทำด้วย action และ reducer
import React, { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "inc": return { count: state.count + 1 };
case "dec": return { count: state.count - 1 };
default: return state;
}
}
export function App() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p data-out>ค่า: {state.count}</p>
<button id="inc" onClick={() => dispatch({ type: "inc" })}>+</button>
<button id="dec" onClick={() => dispatch({ type: "dec" })}>-</button>
</div>
);
}
export const steps = ["#inc", "#inc", "#dec"];
**ผลลัพธ์ที่ได้จากการรันจริง**
ข้อความเริ่มต้น: ค่า: 0
หลังคลิกครั้งที่ 1: ค่า: 1
หลังคลิกครั้งที่ 2: ค่า: 2
หลังคลิกครั้งที่ 3: ค่า: 1
ตัวอย่างที่ 17: custom hook
รวมตรรกะของ state ไว้ในฟังก์ชันที่ขึ้นต้นด้วย use เพื่อนำกลับมาใช้ซ้ำ
import React, { useState } from "react";
function useCounter(start) {
const [count, setCount] = useState(start);
return { count, increment: () => setCount(c => c + 1) };
}
export function App() {
const { count, increment } = useCounter(10);
return (
<div>
<p data-out>ค่าตอนนี้: {count}</p>
<button id="inc" onClick={increment}>เพิ่ม</button>
</div>
);
}
export const steps = ["#inc"];
**ผลลัพธ์ที่ได้จากการรันจริง**
ข้อความเริ่มต้น: ค่าตอนนี้: 10
หลังคลิกครั้งที่ 1: ค่าตอนนี้: 11
ตัวอย่างที่ 18: useMemo
จำผลการคำนวณที่หนักไว้ และคำนวณใหม่เฉพาะเมื่อ dependency เปลี่ยน
import React, { useMemo } from "react";
const numbers = [1, 2, 3, 4, 5];
export function App() {
const total = useMemo(() => numbers.reduce((a, b) => a + b, 0), []);
return <p>ผลรวม = {total}</p>;
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<p>ผลรวม = 15</p>
ตัวอย่างที่ 19: แท็บ
เลือกเนื้อหาจาก object ตามแท็บที่ผู้ใช้กด ตัวอย่างนี้สลับระหว่างแท็ก A และ B
import React, { useState } from "react";
const content = {
a: "เนื้อหาแท็บ A",
b: "เนื้อหาแท็บ B",
};
export function App() {
const [tab, setTab] = useState("a");
return (
<div>
<button id="tab-a" onClick={() => setTab("a")}>แท็บ A</button>
<button id="tab-b" onClick={() => setTab("b")}>แท็บ B</button>
<p data-out>{content[tab]}</p>
</div>
);
}
export const steps = ["#tab-b", "#tab-a"];
**ผลลัพธ์ที่ได้จากการรันจริง**
ข้อความเริ่มต้น: เนื้อหาแท็บ A
หลังคลิกครั้งที่ 1: เนื้อหาแท็บ B
หลังคลิกครั้งที่ 2: เนื้อหาแท็บ A
ตัวอย่างที่ 20: โหลดข้อมูล
โหลดข้อมูลตอน component แสดงครั้งแรก แสดงสถานะกำลังโหลด แล้วแสดงรายการเมื่อโหลดเสร็จ
import React, { useEffect, useState } from "react";
const DATA = ["สมชาย", "สมหญิง", "สมศักดิ์"];
export function App() {
const [loading, setLoading] = useState(true);
const [items, setItems] = useState([]);
const load = () => {
setLoading(true);
setTimeout(() => { setItems(DATA); setLoading(false); }, 0);
};
useEffect(() => { load(); }, []);
return (
<div>
<button id="reload" onClick={load}>โหลดใหม่</button>
<div data-out>{loading ? <p>กำลังโหลด...</p> : <ul>{items.map(n => <li key={n}>{n}</li>)}</ul>}</div>
</div>
);
}
export const steps = ["#reload"];
**ผลลัพธ์ที่ได้จากการรันจริง**
ข้อความเริ่มต้น: กำลังโหลด...
หลังคลิกครั้งที่ 1: สมชายสมหญิงสมศักดิ์
ตัวอย่างที่ 21: หน้าเว็บเล็กๆ ประกอบจาก component
รวมทุกอย่างเป็นหน้าเว็บเดียว มีส่วนหัวพร้อมเมนู ส่วนแนะนำ การ์ดบริการที่สร้างจากข้อมูล และส่วนท้ายเว็บ
import React from "react";
const menu = ["หน้าแรก", "บริการ", "ติดต่อ"];
const services = [
{ id: 1, name: "เว็บไซต์องค์กร", price: 15000 },
{ id: 2, name: "ร้านค้าออนไลน์", price: 25000 },
];
function Header() {
return (
<header style={{ background: "#1a2b4c", color: "#fff", padding: "12px" }}>
<strong>บริษัทตัวอย่าง</strong>
<nav>{menu.map(m => <a key={m} href="#" style={{ marginLeft: 12, color: "#fff" }}>{m}</a>)}</nav>
</header>
);
}
function Hero({ title, subtitle }) {
return (
<section>
<h1>{title}</h1>
<p>{subtitle}</p>
</section>
);
}
function ServiceCard({ name, price }) {
return (
<div style={{ border: "1px solid #ccc", borderRadius: 8, padding: 12, margin: 8 }}>
<h3>{name}</h3>
<p>ราคาเริ่มต้น {price.toLocaleString("en-US")} บาท</p>
</div>
);
}
function Footer() {
return <footer><small>© 2026 บริษัทตัวอย่าง</small></footer>;
}
export function App() {
return (
<div>
<Header />
<main>
<Hero title="ยินดีต้อนรับ" subtitle="เราสร้างเว็บให้ธุรกิจของคุณ" />
<div>{services.map(s => <ServiceCard key={s.id} name={s.name} price={s.price} />)}</div>
</main>
<Footer />
</div>
);
}
**ผลลัพธ์ที่ได้จากการรันจริง**
<div><header style="background:#1a2b4c;color:#fff;padding:12px"><strong>บริษัทตัวอย่าง</strong><nav><a href="#" style="margin-left:12px;color:#fff">หน้าแรก</a><a href="#" style="margin-left:12px;color:#fff">บริการ</a><a href="#" style="margin-left:12px;color:#fff">ติดต่อ</a></nav></header><main><section><h1>ยินดีต้อนรับ</h1><p>เราสร้างเว็บให้ธุรกิจของคุณ</p></section><div><div style="border:1px solid #ccc;border-radius:8px;padding:12px;margin:8px"><h3>เว็บไซต์องค์กร</h3><p>ราคาเริ่มต้น 15,000 บาท</p></div><div style="border:1px solid #ccc;border-radius:8px;padding:12px;margin:8px"><h3>ร้านค้าออนไลน์</h3><p>ราคาเริ่มต้น 25,000 บาท</p></div></div></main><footer><small>© 2026 บริษัทตัวอย่าง</small></footer></div>
ขั้นต่อไป
ขั้นต่อไปให้ใช้ React Router เพื่อแยกหน้า ใช้ fetch เรียก API จริง และใช้ Vite หรือ Next.js เป็นเครื่องมือสร้างโปรเจกต์ เมื่อเข้าใจ state และ props แล้ว การเพิ่มความสามารถให้เว็บจะเป็นเรื่องของการประกอบ component เพิ่มขึ้นเท่านั้น
สรุป
React สร้างหน้าเว็บจาก component ที่รับ props และเก็บ state ได้ เมื่อ state เปลี่ยน React จะ render ส่วนที่เกี่ยวข้องใหม่ ตัวอย่างทั้ง 21 เรื่องครอบคลุมตั้งแต่การแสดงผลจนถึงการประกอบหน้าเว็บที่สมบูรณ์ และทุกผลลัพธ์ในบทความนี้มาจากการรันจริง