ทำไมต้องใช้ Context API ใน React?
เวลาเราเขียน React (ไลบรารีสำหรับสร้างหน้าจอเว็บไซต์) มักจะมีข้อมูลที่ต้องใช้หลายที่ เช่น ข้อมูลผู้ใช้งานที่ล็อกอินอยู่ ถ้าเราส่งข้อมูลนี้ผ่าน Props (การส่งข้อมูลจากแม่ไปลูก) ไปเรื่อยๆ หลายชั้นจะทำให้โค้ดอ่านยากมาก
ลองนึกภาพว่าเราต้องถือของชิ้นหนึ่ง แล้วส่งต่อกันเป็นทอดๆ จากคนหน้าแถวไปคนสุดท้าย ถ้าคนกลางแถวทำตก หรือส่งผิดคน ทุกอย่างจะพังทันที Context API (เครื่องมือสำหรับแชร์ข้อมูลให้ทุกส่วนในแอป) จึงเข้ามาแก้ปัญหานี้
มันเหมือนการมี "กระดานประกาศ" ที่ใครอยากรู้ข้อมูลอะไร ก็แค่เดินมาอ่านที่กระดานได้เลย ไม่ต้องรอให้ใครส่งต่อให้ทีละคน วิธีนี้ช่วยให้โปรเจกต์ของคุณดูสะอาดและจัดการง่ายขึ้นมาก โดยเฉพาะเวลาแอปเริ่มใหญ่ขึ้นครับ
เตรียมตัวด้วย TypeScript ให้ชัวร์
การใช้ TypeScript (ภาษาที่เพิ่มระบบตรวจสอบประเภทข้อมูลให้ JavaScript) ร่วมกับ Context จะช่วยลดบั๊กได้เยอะ เพราะเราจะรู้ล่วงหน้าว่าข้อมูลในกระดานประกาศของเราหน้าตาเป็นอย่างไร ห้ามใส่ข้อมูลมั่วซั่วเด็ดขาด
ก่อนอื่นเราต้องกำหนด Type (รูปแบบโครงสร้างของข้อมูล) ขึ้นมาก่อน เพื่อบอกโปรแกรมว่าเราจะเก็บอะไรบ้าง เช่น ข้อมูลผู้ใช้ต้องมีชื่อและอีเมล ถ้าข้อมูลหายไปหรือใส่ผิดประเภท โปรแกรมจะเตือนเราทันทีตอนเขียนโค้ด
นี่คือจุดที่มือใหม่มักพลาด คือการลืมกำหนดค่าเริ่มต้นให้เป็น null (ค่าว่างเปล่า) ทำให้ตอนดึงข้อมูลไปใช้ โปรแกรมอาจจะฟ้องว่าหาข้อมูลไม่เจอ ดังนั้นเราต้องเตรียมตัวรับมือกับกรณีที่ยังไม่มีข้อมูลด้วยครับ
// กำหนดหน้าตาข้อมูลผู้ใช้
type User = {
name: string;
email: string;
};
// กำหนดหน้าตาของ Context
type AuthContextType = {
user: User | null;
login: (user: User) => void;
logout: () => void;
};
ในโค้ดนี้ เราสร้าง type ขึ้นมาเพื่อระบุว่า AuthContextType ต้องมีข้อมูล user และฟังก์ชัน login กับ logout เพื่อให้ส่วนอื่นของแอปเรียกใช้ได้อย่างถูกต้อง
สร้าง Context และ Provider
ขั้นตอนต่อมาคือการสร้าง createContext (คำสั่งสร้างพื้นที่เก็บข้อมูลส่วนกลาง) ขึ้นมา โดยเราจะใส่ null เข้าไปเป็นค่าเริ่มต้น เพื่อบอกว่าตอนเริ่มแอปยังไม่มีใครล็อกอินเข้ามานั่นเอง
จากนั้นเราต้องทำ Provider (ตัวจ่ายข้อมูลให้ส่วนประกอบลูกๆ) เพื่อห่อหุ้มส่วนของแอปที่ต้องการเข้าถึงข้อมูลนี้ ถ้าไม่ห่อหุ้มไว้ ข้อมูลก็จะส่งไปไม่ถึงลูกๆ ในแอปครับ
มือใหม่มักลืมส่งค่า value เข้าไปใน Provider ทำให้ข้อมูลที่ได้เป็นค่าว่างเปล่าตลอดเวลา ต้องระวังให้ดีว่าทุกครั้งที่สร้าง Provider ต้องส่งข้อมูลที่จำเป็นผ่าน value เสมอครับ
import { createContext, useState } from 'react';
// สร้าง Context พร้อมระบุ Type
export const AuthContext = createContext<AuthContextType | null>(null);
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const [user, setUser] = useState<User | null>(null);
const login = (userData: User) => setUser(userData);
const logout = () => setUser(null);
// ส่งข้อมูลผ่าน value ให้ทุกส่วนที่ถูกห่อหุ้ม
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
};
โค้ดด้านบนคือการสร้างพื้นที่เก็บข้อมูลและจ่ายข้อมูลออกไป โดยใช้ useState (คำสั่งเก็บสถานะข้อมูล) เพื่อให้ข้อมูลอัปเดตได้ตลอดเวลาเมื่อมีการล็อกอินหรือล็อกเอาต์ครับ
สร้าง Custom Hook เพื่อความง่าย
การดึงข้อมูลจาก Context ตรงๆ ทุกครั้งอาจจะน่ารำคาญ เพราะเราต้องเขียนคำสั่งตรวจสอบว่ามันเป็น null หรือไม่ทุกครั้ง เราจึงควรสร้าง Custom Hook (ฟังก์ชันที่เราเขียนขึ้นเองเพื่อเรียกใช้ Logic ซ้ำๆ) มาช่วย
เราจะสร้างฟังก์ชันชื่อ useAuth ขึ้นมา เพื่อดึงข้อมูลจาก Context ได้ง่ายขึ้น ถ้าเผลอเรียกใช้ useAuth นอกเหนือจากที่ห่อหุ้มไว้ เราก็เขียนให้มันแจ้งเตือนข้อผิดพลาดได้เลย ซึ่งช่วยให้เราหาบั๊กได้ไวขึ้นมาก
การทำแบบนี้ทำให้โค้ดในหน้าอื่นๆ สั้นลงและอ่านง่ายขึ้นเยอะครับ แทนที่จะเขียนคำสั่งยาวๆ เราก็แค่เรียกใช้ const { user } = useAuth() ก็ได้ข้อมูลมาใช้งานทันที
import { useContext } from 'react';
// สร้าง Custom Hook เพื่อดึงข้อมูล
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error("ต้องใช้ภายใน AuthProvider เท่านั้น");
}
return context;
};
ฟังก์ชัน useAuth นี้จะทำหน้าที่เช็คให้เราว่า ถ้าไม่มีข้อมูลใน Context ให้รีบเตือนทันที เพื่อป้องกันไม่ให้โปรแกรมพังตอนใช้งานจริงครับ
การนำไปใช้งานจริง
เมื่อเตรียมทุกอย่างเสร็จแล้ว ขั้นตอนสุดท้ายคือการนำ AuthProvider ไปครอบไว้ที่ระดับบนสุดของแอป เพื่อให้ทุกๆ ส่วนของเว็บไซต์เรียกใช้ข้อมูลผู้ใช้งานได้จากทุกที่ครับ
ในหน้าจอส่วนอื่นๆ เราก็แค่ใช้ useAuth เพื่อดึงฟังก์ชัน login หรือข้อมูล user ออกมาใช้ได้เลย ไม่ต้องส่ง Props ต่อกันให้เหนื่อยอีกต่อไป เป็นวิธีที่มืออาชีพใช้กันในโปรเจกต์จริงครับ
จุดที่ต้องระวังคืออย่าใส่ข้อมูลทุกอย่างในโลกไว้ใน Context เดียวกัน เพราะจะทำให้แอปช้าลงได้เมื่อข้อมูลเปลี่ยนบ่อยๆ ให้แยก Context ตามหน้าที่การทำงานของมันจะดีที่สุดครับ
// ในไฟล์ App.tsx
function App() {
return (
<AuthProvider>
<Navbar />
<Profile />
</AuthProvider>
);
}
โค้ดนี้แสดงให้เห็นว่าเราห่อหุ้มแอปด้วย AuthProvider ทำให้ทั้ง Navbar และ Profile สามารถดึงข้อมูลผู้ใช้งานมาแสดงผลได้ทันทีครับ
สรุป: เอาไปปรับใช้ยังไงให้เก่งขึ้น
การใช้ Context API ร่วมกับ TypeScript ไม่ใช่เรื่องยากอย่างที่คิดครับ มันคือการวางระบบระเบียบให้แอปของคุณทำงานได้อย่างเป็นระเบียบและลดโอกาสเกิดบั๊กให้น้อยที่สุด
ลองนำไปใช้ในโปรเจกต์เล็กๆ ของคุณดู เช่น ระบบเก็บสถานะธีม (มืด/สว่าง) หรือระบบตะกร้าสินค้า วิธีนี้จะช่วยให้คุณเข้าใจการไหลของข้อมูลใน React ได้ลึกซึ้งยิ่งขึ้นครับ
หัวใจสำคัญคือการกำหนด Type ให้แม่นยำและการทำ Custom Hook ที่ใช้ง่าย ถ้าคุณฝึกทำแบบนี้บ่อยๆ คุณจะกลายเป็นโปรแกรมเมอร์ที่เขียนโค้ดได้สะอาดและน่าทำงานด้วยแน่นอนครับ