ทำความรู้จักกับ TanStack Query และเหตุผลที่ต้องใช้
เวลาเราเขียนเว็บที่ต้องดึงข้อมูลจากอินเทอร์เน็ต เรามักจะเจอปัญหาเรื่องการจัดการ Server State (ข้อมูลที่มาจากเซิร์ฟเวอร์หรือคอมพิวเตอร์แม่ข่าย) ให้ทันสมัยอยู่เสมอ หากเราเขียนโค้ดแบบปกติ เราต้องคอยเขียนคำสั่งเพื่อดึงข้อมูลใหม่ทุกครั้งที่ผู้ใช้กดปุ่ม หรือต้องคอยเช็กว่าข้อมูลที่ได้มานั้นผิดพลาดหรือยังโหลดไม่เสร็จ
ลองนึกภาพว่าคุณกำลังเปิดแอปสั่งอาหาร ถ้าคุณกดรีเฟรชหน้าจอแล้วแอปต้องโหลดใหม่ทั้งหมดตั้งแต่ต้น ทั้งที่ข้อมูลเดิมยังใช้ได้อยู่ แบบนั้นคงเสียเวลามาก TanStack Query (เครื่องมือจัดการข้อมูลจากเซิร์ฟเวอร์ให้เป็นระเบียบ) เข้ามาแก้ปัญหานี้โดยการเก็บข้อมูลไว้ใน Cache (หน่วยความจำชั่วคราวที่ช่วยให้เข้าถึงข้อมูลได้เร็วขึ้น) เพื่อให้แอปของคุณทำงานได้ลื่นไหลและดูเป็นมืออาชีพ
เหตุผลที่เราต้องใช้เครื่องมือนี้ เพราะมันช่วยลดความซับซ้อนในการเขียนโค้ดแบบเดิมที่ต้องใช้ useState (คำสั่งเก็บสถานะข้อมูลใน React) ร่วมกับ useEffect (คำสั่งสั่งให้ทำงานเมื่อเกิดเหตุการณ์บางอย่าง) จำนวนมาก มันจะเข้ามาจัดการเรื่องการโหลดข้อมูล การแจ้งเตือนเมื่อเกิดข้อผิดพลาด และการดึงข้อมูลใหม่โดยอัตโนมัติให้เราเอง
การติดตั้งและตั้งค่าเริ่มต้นให้โปรเจกต์
ขั้นตอนแรกคือการติดตั้งไลบรารี (ชุดคำสั่งที่เขียนไว้ให้เรานำไปใช้ต่อ) เข้าไปในโปรเจกต์ผ่าน Terminal (หน้าจอสำหรับพิมพ์คำสั่งคอมพิวเตอร์) ของคุณ หากใช้ npm เป็นเครื่องมือจัดการแพ็กเกจ ให้พิมพ์คำสั่ง npm install @tanstack/react-query เพื่อเริ่มใช้งาน
เมื่อติดตั้งเสร็จแล้ว คุณต้องนำ QueryClientProvider (ตัวห่อหุ้มที่ทำให้ทุกส่วนของแอปเข้าถึงระบบจัดการข้อมูลได้) ไปครอบไว้ที่ไฟล์หลักของแอป วิธีนี้จะทำให้ทุกคอมโพเนนต์ (ชิ้นส่วนหน้าจอ) ในแอปสามารถเรียกใช้ฟังก์ชันดึงข้อมูลได้ทันทีโดยไม่ต้องส่งค่าต่อกันไปมาให้ยุ่งยาก
มือใหม่หลายคนมักลืมครอบตัว Provider นี้ไว้ที่ชั้นนอกสุดของแอป ทำให้พอเรียกใช้ฟังก์ชันดึงข้อมูลทีไรก็จะเจอข้อผิดพลาดตลอดเวลา อย่าลืมเช็กให้ดีว่าคุณได้นำเข้าไฟล์และครอบโค้ดไว้ใน index.js หรือ App.js เรียบร้อยแล้วก่อนจะเริ่มเขียนโค้ดส่วนอื่น
// นำเข้าเครื่องมือที่จำเป็น
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// สร้างตัวจัดการข้อมูล
const queryClient = new QueryClient();
// นำไปครอบส่วนประกอบหลักของแอป
function App() {
return (
<QueryClientProvider client={queryClient}>
<MyComponent />
</QueryClientProvider>
);
}
การดึงข้อมูลด้วย useQuery
หัวใจสำคัญของเครื่องมือนี้คือฟังก์ชันที่ชื่อว่า useQuery (คำสั่งสำหรับดึงข้อมูล) ซึ่งทำหน้าที่เหมือนพนักงานส่งของที่คอยไปเอาข้อมูลจากเซิร์ฟเวอร์มาให้เรา โดยเราต้องระบุ Query Key (ชื่อเฉพาะสำหรับเรียกข้อมูลชุดนั้น) เพื่อให้มันจำได้ว่าข้อมูลนี้คืออะไร
เมื่อเราใช้ useQuery มันจะคืนค่าสถานะต่างๆ กลับมาให้เราใช้ทันที เช่น isLoading (สถานะกำลังโหลด) เพื่อบอกว่าข้อมูลยังมาไม่ถึง หรือ error (สถานะเมื่อเกิดข้อผิดพลาด) เพื่อบอกว่าการดึงข้อมูลมีปัญหา คุณสามารถนำสถานะเหล่านี้ไปแสดงข้อความบอกผู้ใช้ได้ทันทีว่าตอนนี้แอปกำลังทำอะไรอยู่
จุดที่มือใหม่มักพลาดคือการลืมใส่ Query Key ให้เป็นรูปแบบ Array (ชุดข้อมูลที่เก็บค่าหลายค่าไว้ด้วยกัน) เช่น ['users'] ซึ่งถ้าลืมใส่หรือใส่ไม่ถูกต้อง ระบบจะไม่สามารถจัดการเรื่องการจำข้อมูลไว้ในแคชได้ ทำให้แอปทำงานช้าลงโดยไม่จำเป็น
import { useQuery } from '@tanstack/react-query';
function UserList() {
// ดึงข้อมูลผู้ใช้จาก API
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('https://api.example.com/users').then(res => res.json())
});
if (isLoading) return <div>กำลังโหลด...</div>;
if (error) return <div>เกิดข้อผิดพลาด!</div>;
return <div>{data.map(user => <p>{user.name}</p>)}</div>;
}
การจัดการ Cache และ Background Refetching
Background Refetching (การดึงข้อมูลใหม่แบบเงียบๆ ในเบื้องหลัง) คือฟีเจอร์ที่ทำให้แอปของคุณดูทันสมัยอยู่เสมอโดยที่ผู้ใช้ไม่ต้องกดรีเฟรชเอง ทุกครั้งที่คุณสลับหน้าจอไปมา ตัวไลบรารีจะเช็กให้เองว่าข้อมูลในแคชเก่าไปหรือยัง ถ้าเก่าแล้วมันจะไปดึงข้อมูลใหม่มาอัปเดตให้ทันที
ถ้าคุณสงสัยว่าทำไมข้อมูลถึงอัปเดตเอง ทั้งที่เราไม่ได้เขียนคำสั่งอะไรเพิ่ม นั่นเพราะค่าตั้งต้นของ staleTime (ระยะเวลาที่ข้อมูลยังถือว่าสดใหม่) ถูกตั้งไว้ที่ 0 หมายความว่าข้อมูลจะถูกมองว่าเก่าทันทีหลังจากดึงมา คุณสามารถปรับค่านี้ให้มากขึ้นเพื่อให้แอปดึงข้อมูลใหม่น้อยลงและประหยัดการใช้งานอินเทอร์เน็ต
การเข้าใจการทำงานของแคชจะช่วยให้คุณออกแบบ UX (ประสบการณ์การใช้งานของคนใช้แอป) ได้ดีขึ้นมาก เพราะผู้ใช้จะได้รับข้อมูลที่รวดเร็วจากการดึงข้อมูลในแคชมาแสดงก่อน แล้วค่อยอัปเดตข้อมูลจริงให้เมื่อการดึงข้อมูลจากเซิร์ฟเวอร์สำเร็จ ซึ่งเป็นเทคนิคมาตรฐานที่โปรแกรมเมอร์มืออาชีพเขาใช้กัน
การจัดการสถานะ Loading และ Error ให้สวยงาม
ในการเขียนซอฟต์แวร์จริง การแสดงหน้าจอขาวโพลนเวลาข้อมูลยังไม่มาคือสิ่งต้องห้าม คุณควรใช้สถานะ isLoading หรือ isFetching (สถานะการดึงข้อมูลที่เกิดขึ้นซ้ำ) เพื่อแสดง Skeleton Screen (โครงร่างหน้าจอที่แสดงก่อนข้อมูลจริงจะมา) หรือตัวหมุนโหลดข้อมูลเพื่อให้ผู้ใช้รู้ว่าแอปไม่ได้ค้าง
สำหรับกรณีที่การดึงข้อมูลล้มเหลว เช่น เซิร์ฟเวอร์ล่มหรืออินเทอร์เน็ตของผู้ใช้หลุด คุณควรมีหน้าจอแจ้งเตือนที่ชัดเจนและมีปุ่มให้กดลองใหม่ (Retry) ได้ การใช้ error object ที่ได้จาก useQuery จะช่วยให้คุณเข้าถึงข้อความแจ้งเตือนที่เซิร์ฟเวอร์ส่งกลับมา ทำให้บอกผู้ใช้ได้ตรงจุดว่าเกิดอะไรขึ้น
จำไว้ว่าโปรแกรมเมอร์ที่ดีไม่ได้มองแค่ว่าโค้ดทำงานได้ไหม แต่ต้องมองว่าถ้าเกิดเหตุการณ์ไม่คาดฝัน แอปจะยังใช้งานต่อได้หรือไม่ การจัดการสถานะที่ผิดพลาดให้เป็นมิตรกับผู้ใช้จะทำให้ Portfolio ของคุณดูน่าเชื่อถือและผ่านการคิดมาอย่างรอบคอบในการสัมภาษณ์งาน
// ตัวอย่างการแสดงผลตามสถานะ
return (
<div>
{isLoading && <p>กำลังดึงข้อมูล...</p>}
{error && <p>มีบางอย่างผิดพลาด: {error.message}</p>}
{data && <ul>{data.map(item => <li key={item.id}>{item.name}</li>)}</ul>}
</div>
);
สรุป: เปลี่ยนโปรเจกต์ธรรมดาให้เป็นแอปที่ลื่นไหล
การใช้ TanStack Query เปลี่ยนวิธีการพัฒนาเว็บของคุณไปโดยสิ้นเชิง จากเดิมที่คุณต้องเขียนโค้ดจัดการข้อมูลที่ยุ่งเหยิง ตอนนี้คุณมีเครื่องมือที่ช่วยจัดการทั้งการจำข้อมูล การดึงข้อมูลใหม่ และสถานะต่างๆ ให้โดยอัตโนมัติ ทำให้คุณมีเวลาไปโฟกัสกับการออกแบบฟีเจอร์อื่นๆ ที่สำคัญกว่า
ลองนำไปประยุกต์ใช้กับโปรเจกต์ใน Portfolio ของคุณ เช่น แอปแสดงรายการสินค้า หรือแอปพยากรณ์อากาศ คุณจะเห็นความแตกต่างทันทีว่าแอปของคุณจะทำงานได้ลื่นไหลขึ้น ผู้ใช้แทบจะไม่รู้สึกถึงการรอคอยข้อมูล เพราะระบบแคชที่ฉลาดของมันได้เตรียมข้อมูลไว้ให้พร้อมใช้งานอยู่เสมอ
ก้าวต่อไปของคุณคือการฝึกฝน ลองสร้างโปรเจกต์ดึงข้อมูลจาก API สาธารณะ (ข้อมูลฟรีที่เปิดให้คนทั่วไปใช้งาน) แล้วลองปรับค่า staleTime ดูว่าแอปมีพฤติกรรมอย่างไร เมื่อคุณทำจนคล่องแล้ว คุณจะพบว่าการจัดการ Server State ไม่ใช่เรื่องน่ากลัวอีกต่อไป และคุณก็พร้อมที่จะก้าวเข้าสู่การเป็นโปรแกรมเมอร์ที่เขียนโค้ดได้อย่างมีประสิทธิภาพมากขึ้นครับ