# TanStack Query คืออะไร? คู่มือจัดการ Server State ใน Next.js สำหรับนักพัฒนา SME ปี 2026
ปัญหาหนึ่งที่นักพัฒนา Next.js หลายคนเจอบ่อยคือการจัดการข้อมูลที่มาจาก API Server หรือที่เรียกว่า "Server State" ไม่ว่าจะเป็นการ fetch ข้อมูล การอัปเดตแบบ real-time การ cache ข้อมูลเพื่อประสิทธิภาพ หรือการจัดการสถานะ loading/error
TanStack Query (หรือที่เดิมเรียกว่า React Query) คือ Library ที่แก้ปัญหาเหล่านี้ได้อย่างสง่างาม ด้วย API ที่เรียบง่ายแต่ทรงพลัง ช่วยลด boilerplate code ได้มหาศาลและทำให้แอปพลิเคชันมีประสิทธิภาพสูงขึ้นโดยอัตโนมัติ
ในปี 2026 TanStack Query กลายเป็นมาตรฐานสำหรับการจัดการ Server State ในแอป React/Next.js ที่มืออาชีพ บทความนี้จะพาคุณเรียนรู้ตั้งแต่พื้นฐาน วิธีติดตั้ง การใช้งาน Hooks หลัก ไปจนถึง Best Practices สำหรับโปรเจกต์จริง
Server State vs Client State คืออะไร?
ก่อนเริ่มเรียน TanStack Query ต้องเข้าใจความแตกต่างก่อน
Client State คือข้อมูลที่อยู่ใน Browser เท่านั้น เช่น สถานะ Sidebar เปิด/ปิด, Form input ที่ผู้ใช้กรอก, หรือ Theme: Dark/Light โดยมักจัดการด้วย useState หรือ Zustand
Server State คือข้อมูลที่มาจาก Server และต้องซิงค์อยู่ตลอดเวลา เช่น รายการสินค้าจาก Database, ข้อมูลผู้ใช้, หรือสถิติ Dashboard ซึ่งต้องจัดการทั้ง loading, error, caching, refetching และ background updates
TanStack Query ถูกออกแบบมาเฉพาะสำหรับ Server State นี้เอง
TanStack Query คืออะไร?
TanStack Query เป็น Data Synchronization Library ที่ช่วยจัดการ Server State ใน React/Next.js โดยมีฟีเจอร์หลัก ได้แก่:
วิธีติดตั้ง TanStack Query ใน Next.js
ขั้นตอนที่ 1: ติดตั้ง Package
```bash
npm install @tanstack/react-query @tanstack/react-query-devtools
```
ขั้นตอนที่ 2: ตั้งค่า QueryClient Provider
สร้างไฟล์ `app/providers.tsx`:
```typescript
'use client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { useState } from 'react'
export function Providers({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(() => new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
retry: 2,
},
},
}))
return (
<QueryClientProvider client={queryClient}>
{children}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}
```
ใน `app/layout.tsx` ให้ห่อ children ด้วย `<Providers>` เพื่อให้ทุก Component เข้าถึง QueryClient ได้
ขั้นตอนที่ 3: ใช้ useQuery เพื่อ Fetch ข้อมูล
```typescript
'use client'
import { useQuery } from '@tanstack/react-query'
async function fetchProducts() {
const res = await fetch('/api/products')
if (!res.ok) throw new Error('Network response error')
return res.json()
}
export function ProductList() {
const { data, isLoading, error } = useQuery({
queryKey: ['products'],
queryFn: fetchProducts,
staleTime: 5 * 60 * 1000, // Cache 5 นาที
})
if (isLoading) return <div>กำลังโหลด...</div>
if (error) return <div>เกิดข้อผิดพลาด: {error.message}</div>
return (
<ul>
{data?.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
)
}
```
useMutation: จัดการ Create/Update/Delete
```typescript
import { useMutation, useQueryClient } from '@tanstack/react-query'
export function CreateProductForm() {
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: async (newProduct) => {
const res = await fetch('/api/products', {
method: 'POST',
body: JSON.stringify(newProduct),
headers: { 'Content-Type': 'application/json' }
})
return res.json()
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['products'] })
},
})
return (
<button
onClick={() => mutation.mutate({ name: 'สินค้าใหม่', price: 100 })}
disabled={mutation.isPending}
>
{mutation.isPending ? 'กำลังบันทึก...' : 'เพิ่มสินค้า'}
</button>
)
}
```
เปรียบเทียบ: TanStack Query vs วิธีแบบเดิม
| Feature | useState + useEffect | TanStack Query |
|---------|---------------------|----------------|
| Caching | ต้องเขียนเอง | อัตโนมัติ |
| Loading State | ต้องจัดการเอง | ในตัว |
| Error Handling | ต้องเขียนเอง | ในตัว + Auto Retry |
| Background Refetch | ยาก | อัตโนมัติ |
| Deduplication | ไม่มี | อัตโนมัติ |
| DevTools | ไม่มี | มี (React Query DevTools) |
| Infinite Scroll | ต้องเขียนเอง | useInfiniteQuery ในตัว |
| Code Amount | มาก | น้อยกว่า 3-5 เท่า |
Best Practices สำหรับโปรเจกต์จริง
1. จัดระเบียบ Query Keys ด้วย Query Key Factory
```typescript
// lib/queryKeys.ts
export const productKeys = {
all: ['products'] as const,
lists: () => [...productKeys.all, 'list'] as const,
detail: (id: number) => [...productKeys.all, 'detail', id] as const,
}
```
2. แยก Fetch Function เป็น Service File
```typescript
// services/productService.ts
export const productService = {
getAll: () => fetch('/api/products').then(r => r.json()),
getById: (id: number) => fetch(`/api/products/${id}`).then(r => r.json()),
}
```
3. สร้าง Custom Hook ต่อ Resource
```typescript
// hooks/useProducts.ts
export function useProducts() {
return useQuery({
queryKey: productKeys.lists(),
queryFn: productService.getAll,
})
}
```
การแยก Query Keys และ Service ออกมาเป็นไฟล์ต่างหากช่วยให้โค้ดอ่านง่าย บำรุงรักษาง่าย และ Reuse ได้ในหลาย Component
การใช้งานขั้นสูง: useInfiniteQuery
```typescript
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['products', 'infinite'],
queryFn: ({ pageParam = 1 }) =>
fetch(`/api/products?page=${pageParam}`).then(r => r.json()),
getNextPageParam: (lastPage) => lastPage.nextPage,
initialPageParam: 1,
})
```
useInfiniteQuery ทำให้การสร้าง Infinite Scroll หรือ Load More ง่ายมากโดยไม่ต้องจัดการ State ซับซ้อน
สรุปและ CTA
TanStack Query เป็น Library ที่ทุกโปรเจกต์ Next.js ที่ต้องการ fetch ข้อมูลจาก API ควรใช้ มันช่วยลดโค้ดที่ซับซ้อน จัดการ State ที่ยุ่งยาก และเพิ่มประสิทธิภาพแอปพลิเคชันโดยอัตโนมัติ
สิ่งที่ควรจำ:
หากต้องการพัฒนาแอปพลิเคชัน Next.js ที่ทรงพลัง ปลอดภัย และมีประสิทธิภาพสูงสำหรับธุรกิจของคุณ ติดต่อทีม ADS FIT เรามีผู้เชี่ยวชาญด้าน Laravel และ Next.js พร้อมออกแบบและพัฒนาระบบที่ตอบโจทย์ธุรกิจ SME ไทยโดยเฉพาะ
