Prop Drilling คืออะไร ทำไมต้องรีบแก้
เวลาเราเขียน React เรามักจะแบ่งโค้ดเป็นส่วนเล็ก ๆ ที่เรียกว่า Component (ชิ้นส่วนหน้าจอที่นำไปใช้ซ้ำได้) ปัญหามันจะเกิดเมื่อเรามีข้อมูลที่ต้องส่งจาก Component แม่ ไปยังลูก หลาน หรือเหลนที่อยู่ลึกมาก ๆ
เปรียบเทียบง่าย ๆ เหมือนคุณแม่ถือของขวัญไว้ แล้วต้องส่งต่อให้ลูกคนกลาง เพื่อให้ลูกคนกลางส่งต่อให้หลานคนเล็กอีกที หากหลานคนเล็กต้องการของขวัญชิ้นนั้น เราต้องส่งผ่านมือทุกคนในบ้านไปเรื่อย ๆ นี่คือสิ่งที่เรียกว่า Prop Drilling (การส่งข้อมูลผ่าน Component ที่ไม่ได้ใช้ข้อมูลนั้นจริง ๆ เพียงแค่ส่งต่อให้คนอื่น)
ถ้าโปรเจกต์เราเริ่มใหญ่ขึ้น การตามหาว่าข้อมูลถูกส่งมาจากไหนจะกลายเป็นฝันร้ายทันที Prop Drilling ทำให้โค้ดของเราดูรกและแก้ไขยากมาก หากเราเปลี่ยนชื่อข้อมูลจุดหนึ่ง เราต้องคอยตามแก้ในทุก Component ที่เป็นทางผ่านทั้งหมด ซึ่งเสียเวลาและเสี่ยงต่อการเกิดบั๊ก (ข้อผิดพลาดของโปรแกรม) มากครับ
รู้จักกับ Context API เครื่องมือแก้ปัญหา
Context API (ตัวช่วยส่งข้อมูลข้ามลำดับชั้นของ Component โดยตรง) คือวิธีแก้ปัญหาที่ React เตรียมไว้ให้เรา ไม่ต้องส่งข้อมูลผ่านคนกลางอีกต่อไป มันเปรียบเหมือนการวางของไว้ที่ส่วนกลางของบ้าน ใครในบ้านที่อยากได้ก็เดินมาหยิบเองได้เลย ไม่ต้องรอให้ใครส่งต่อให้
การใช้ Context ช่วยให้เราไม่ต้องกังวลเรื่องโครงสร้างหน้าจอที่ซับซ้อน เราสามารถดึงข้อมูลที่ต้องการออกมาใช้ที่ไหนก็ได้ในแอปพลิเคชันของเรา ทำให้โค้ดสะอาดขึ้นและจัดการข้อมูลได้ง่ายกว่าเดิมมากครับ
แต่ต้องระวังไว้ว่าการใช้ Context ไม่ใช่คำตอบสำหรับทุกอย่าง หากข้อมูลนั้นใช้แค่ใน Component ใกล้ ๆ กัน การส่ง Props (ค่าที่ส่งจากแม่ไปลูก) แบบปกติก็ยังเป็นวิธีที่เหมาะสมกว่า ใช้ Context เมื่อข้อมูลนั้นต้องใช้ในหลายที่ที่อยู่ห่างกันเท่านั้น เพื่อประสิทธิภาพที่ดีที่สุดครับ
สร้าง Context และ Provider เตรียมส่งข้อมูล
ขั้นตอนแรกเราต้องสร้าง Context ขึ้นมาก่อน แล้วใช้ Provider (ตัวห่อหุ้มที่ทำหน้าที่แจกจ่ายข้อมูล) ครอบ Component ทั้งหมดที่ต้องการใช้ข้อมูลนั้น ข้อมูลที่อยู่ใน Provider จะถูกส่งไปให้ลูกหลานทุกคนที่อยู่ข้างในโดยอัตโนมัติ
ลองดูตัวอย่างการสร้าง Context สำหรับเก็บข้อมูลผู้ใช้งานกันครับ:
import { createContext } from 'react';
// สร้าง Context เริ่มต้นด้วยค่าว่าง
export const UserContext = createContext(null);
// สร้าง Provider เพื่อส่งข้อมูล
export function UserProvider({ children }) {
const user = { name: 'สมชาย', role: 'Developer' };
return (
<UserContext.Provider value={user}>
{children}
</UserContext.Provider>
);
}
ในโค้ดนี้เราสร้าง UserContext ขึ้นมาเป็นตัวกลาง และสร้าง UserProvider เพื่อห่อหุ้ม Component อื่น ๆ โดยส่งค่า user ผ่าน value เพื่อให้ลูกหลานเข้าถึงข้อมูลนี้ได้ง่าย ๆ ครับ
ดึงข้อมูลไปใช้ด้วย useContext
เมื่อเรามี Provider แล้ว การดึงข้อมูลไปใช้ก็ง่ายมาก เราเพียงแค่เรียกใช้ Hook (ฟังก์ชันพิเศษของ React) ที่ชื่อว่า useContext ใน Component ที่เราต้องการข้อมูลนั้นโดยตรง ไม่ต้องผ่านลำดับชั้นอีกต่อไป
ดูตัวอย่างการดึงข้อมูลมาแสดงผลในหน้าจอครับ:
import { useContext } from 'react';
import { UserContext } from './UserProvider';
function Profile() {
// ดึงข้อมูลจาก Context มาใช้
const user = useContext(UserContext);
return (
<div>
<p>สวัสดีคุณ: {user.name}</p>
</div>
);
}
เห็นไหมครับว่า Profile ไม่ต้องรับค่าอะไรจากแม่เลย มันแค่เรียก useContext แล้วได้ข้อมูลมาทันที นี่คือพลังของ Context API ที่ช่วยให้ชีวิตโปรแกรมเมอร์ง่ายขึ้นเยอะครับ
ข้อควรระวังสำหรับมือใหม่
จุดที่มือใหม่มักพลาดคือการใส่ข้อมูลทุกอย่างลงใน Context อันเดียว ซึ่งจะทำให้แอปพลิเคชันช้าลงโดยไม่จำเป็น เพราะเมื่อข้อมูลใน Context เปลี่ยน Component ทุกตัวที่ดึงข้อมูลไปใช้จะทำการ Re-render (วาดหน้าจอใหม่) ทันทีครับ
คำแนะนำคือให้แยก Context ตามประเภทของข้อมูล เช่น มี AuthContext สำหรับข้อมูลผู้ใช้ และ ThemeContext สำหรับสีหน้าจอ อย่าเอามารวมกันในที่เดียวเด็ดขาดครับ อีกอย่างคืออย่าลืมใส่ค่าเริ่มต้น (default value) ให้ถูกต้องตอนสร้าง Context เพื่อป้องกันข้อผิดพลาดเวลาลืมใส่ Provider
หากคุณเริ่มรู้สึกว่าต้องสร้าง Context เยอะเกินไป จนจัดการยาก นั่นอาจเป็นสัญญาณว่าโปรเจกต์ของคุณใหญ่ขึ้นจนต้องมองหาเครื่องมือจัดการสถานะ (State Management) อื่น ๆ เช่น Zustand หรือ Redux ในอนาคตครับ
สรุป: การนำไปใช้จริง
สรุปง่าย ๆ คือ Context API เหมาะสำหรับข้อมูลที่ใช้ร่วมกันทั้งแอป เช่น ข้อมูลผู้ใช้งาน, ภาษาที่เลือกใช้ หรือธีมหน้าจอ (มืด/สว่าง) การใช้งานจริงให้เริ่มจากสร้าง Provider ครอบที่ไฟล์หลัก (เช่น App.js) แล้วใช้ useContext ดึงข้อมูลในส่วนที่ต้องการ
สมมติคุณทำแอปจัดการคลังสินค้า คุณควรใช้ Context เก็บข้อมูล "สถานะการล็อกอิน" เพื่อให้ทุกหน้าจอรู้ว่าใครเป็นคนใช้งาน แต่ข้อมูล "รายการสินค้า" ในหน้าตาราง ควรใช้ Props ปกติหรือ State ในหน้าจอนั้น ๆ เพื่อให้โค้ดทำงานได้รวดเร็วและไม่ซับซ้อนเกินไป
การฝึกเขียน Context ให้คล่องเป็นทักษะสำคัญที่โปรแกรมเมอร์จูเนียร์ต้องมี ลองนำไปใช้ในโปรเจกต์เล็ก ๆ ของตัวเองดูครับ แล้วคุณจะเห็นว่าการบริหารจัดการข้อมูลใน React ไม่ได้ยากอย่างที่คิด แค่ต้องเข้าใจหลักการและเลือกใช้ให้ถูกที่ครับ