React Query: ปฏิวัติการจัดการข้อมูลด้วย `useQuery`

 

ในโลกของการพัฒนาเว็บสมัยใหม่ การจัดการสถานะข้อมูลฝั่งไคลเอ็นต์ (client-side data) ที่ซับซ้อนและมีการเรียกใช้ API บ่อยครั้งเป็นความท้าทายที่นักพัฒนาต้องเผชิญ **TanStack React Query** (เดิมคือ React Query) ได้เข้ามาเปลี่ยนแปลงวิธีการจัดการข้อมูลเหล่านี้อย่างสิ้นเชิง ด้วย hooks ที่ทรงพลัง โดยเฉพาะอย่างยิ่ง **`useQuery`** ที่ช่วยให้เราสามารถจัดการ fetching, caching, synchronizing, และ updating server state ได้อย่างง่ายดายและมีประสิทธิภาพ

บทความนี้จะแนะนำให้คุณรู้จักกับ `useQuery` และแสดงให้เห็นว่ามันสามารถทำให้โค้ดของคุณสะอาดขึ้น มีประสิทธิภาพมากขึ้น และประสบการณ์ผู้ใช้ดีขึ้นได้อย่างไร

-----

### ทำไมต้องใช้ TanStack React Query?

ก่อนที่เราจะเจาะลึกถึง `useQuery` เรามาดูกันว่าทำไม React Query ถึงเป็นที่นิยมและมีความสำคัญ:

  * **Caching อัตโนมัติ:** จัดการแคชข้อมูลที่ดึงมาแล้วโดยอัตโนมัติ ลดการเรียก API ซ้ำซ้อน
  * **Background Refetching:** อัปเดตข้อมูลในเบื้องหลังเพื่อให้ข้อมูลเป็นปัจจุบันอยู่เสมอ โดยไม่บล็อก UI
  * **Optimistic Updates:** ทำให้ UI ตอบสนองได้รวดเร็วขึ้นโดยการอัปเดตข้อมูลทันที และย้อนกลับหากเกิดข้อผิดพลาด
  * **Devtools:** มีเครื่องมือ Devtools ที่ยอดเยี่ยมสำหรับการตรวจสอบสถานะของ Query และ Cache
  * **จัดการสถานะได้ง่ายขึ้น:** ลด boilerplate code ที่เกี่ยวข้องกับการ fetching data (loading, error, success states)
  * **ประสิทธิภาพที่ดีขึ้น:** ช่วยให้แอปพลิเคชันของคุณทำงานได้เร็วและราบรื่นขึ้น

-----

### การเริ่มต้นใช้งาน

ก่อนอื่น คุณต้องติดตั้ง TanStack React Query ในโปรเจกต์ของคุณ:

```bash
npm install @tanstack/react-query
# หรือ
yarn add @tanstack/react-query
```

จากนั้น คุณต้องห่อหุ้มแอปพลิเคชันของคุณด้วย **`QueryClientProvider`** เพื่อให้ `useQuery` สามารถเข้าถึง QueryClient ได้:

```jsx
// src/main.jsx หรือ src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
import './index.css';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; // ไม่บังคับ

const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root')).render(
  
    
      
       {/* แสดง Devtools */}
    
  ,
);
```

-----

### ทำความเข้าใจกับ `useQuery`

`useQuery` เป็น React Hook ที่ใช้สำหรับ "fetching" ข้อมูลจากเซิร์ฟเวอร์ มันจะส่งคืนสถานะของ Query (loading, error, success) พร้อมกับข้อมูลที่ได้มา

**โครงสร้างพื้นฐาน:**

```javascript
const { data, isLoading, isError, error, isSuccess, status } = useQuery({
  queryKey: ['uniqueKey'],
  queryFn: async () => {
    // ฟังก์ชันสำหรับ fetch ข้อมูล
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  },
  // options เพิ่มเติม (เช่น staleTime, cacheTime, retry, enabled ฯลฯ)
});
```

**พารามิเตอร์ที่สำคัญ:**

1.  **`queryKey` (Array):**

      * นี่คือ "**คีย์**" ที่ไม่ซ้ำกันสำหรับ Query ของคุณ
      * React Query ใช้ `queryKey` เพื่อจัดการ Caching, Refetching และ Shared State
      * ควรเป็น Array เสมอ หากข้อมูลที่คุณดึงมาขึ้นอยู่กับพารามิเตอร์ใดๆ ให้รวมพารามิเตอร์เหล่านั้นไว้ใน `queryKey` ด้วย

    ตัวอย่าง:

      * `['todos']`
      * `['todo', todoId]`
      * `['posts', { type: 'published', authorId: 123 }]`

2.  **`queryFn` (Function):**

      * ฟังก์ชัน `async` ที่รับผิดชอบในการ fetch ข้อมูล
      * จะต้องคืนค่าเป็น Promise ที่ Resolve ด้วยข้อมูล หรือ Reject ด้วย Error

**ค่าที่ส่งคืนจาก `useQuery`:**

  * **`data`:** ข้อมูลที่ดึงมาได้เมื่อ Query สำเร็จ (จะเป็น `undefined` ในขณะที่ `isLoading` หรือ `isError`)
  * **`isLoading` / `isPending`:** (ใน v5 เปลี่ยนเป็น **`isPending`** เพื่อให้ความหมายชัดเจนขึ้นว่าอยู่ในสถานะรอ) Boolean ที่ระบุว่า Query กำลังอยู่ในระหว่างการ fetch ข้อมูลครั้งแรก
  * **`isError`:** Boolean ที่ระบุว่า Query มีข้อผิดพลาดเกิดขึ้น
  * **`error`:** อ็อบเจกต์ Error หาก `isError` เป็น `true`
  * **`isSuccess`:** Boolean ที่ระบุว่า Query สำเร็จและมีข้อมูลพร้อมใช้งาน
  * **`status`:** สถานะปัจจุบันของ Query (`'pending'`, `'error'`, `'success'`)

-----

### ตัวอย่างการใช้งานจริง

มาดูตัวอย่างการดึงข้อมูลรายชื่อโพสต์จาก API ง่ายๆ:

```jsx
// src/components/PostsList.jsx
import React from 'react';
import { useQuery } from '@tanstack/react-query';

async function fetchPosts() {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  if (!response.ok) {
    throw new Error('Failed to fetch posts');
  }
  return response.json();
}

function PostsList() {
  const { data: posts, isLoading, isError, error } = useQuery({
    queryKey: ['posts'],
    queryFn: fetchPosts,
  });

  if (isLoading) {
    return 
Loading posts...
; } if (isError) { return
Error: {error.message}
; } return (

Posts

    {posts.map((post) => (
  • {post.title}

    {post.body}

  • ))}
); } export default PostsList; ``` **คำอธิบาย:** 1. เราสร้างฟังก์ชัน `fetchPosts` แยกออกมาเพื่อทำหน้าที่เรียก API 2. เรียกใช้ `useQuery` โดยมี **`queryKey`** เป็น `['posts']` และ **`queryFn`** เป็น `fetchPosts` 3. ตรวจสอบสถานะ **`isLoading`**, **`isError`** และแสดง UI ที่เหมาะสม 4. เมื่อข้อมูลพร้อมใช้งาน (`isSuccess` เป็น `true`) เราก็สามารถเข้าถึง `posts` และนำไปแสดงผลได้เลย ----- ### การจัดการพารามิเตอร์ใน `queryKey` บ่อยครั้งที่เราต้องการดึงข้อมูลโดยอิงจาก ID หรือพารามิเตอร์อื่นๆ `queryKey` สามารถจัดการสิ่งนี้ได้อย่างง่ายดาย: ```jsx // src/components/PostDetail.jsx import React from 'react'; import { useQuery } from '@tanstack/react-query'; async function fetchPostById(postId) { const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`); if (!response.ok) { throw new Error(`Failed to fetch post with ID: ${postId}`); } return response.json(); } function PostDetail({ postId }) { const { data: post, isLoading, isError, error } = useQuery({ queryKey: ['post', postId], // คีย์จะเปลี่ยนไปตาม postId queryFn: () => fetchPostById(postId), // ส่ง postId เข้าไปในฟังก์ชัน fetch enabled: !!postId, // จะเรียก Query ก็ต่อเมื่อ postId มีค่า (ไม่เป็น null/undefined) }); if (isLoading) { return
Loading post...
; } if (isError) { return
Error: {error.message}
; } if (!post) { // กรณีที่ postId ไม่มีค่าตั้งแต่แรก return
Please select a post.
} return (

{post.title}

{post.body}

); } export default PostDetail; ``` **คำอธิบายเพิ่มเติม:** * **`queryKey: ['post', postId]`:** เมื่อ `postId` เปลี่ยนไป React Query จะรู้ว่านี่คือ Query ใหม่และจะทำการ fetch ข้อมูลใหม่ * **`queryFn: () => fetchPostById(postId)`:** เราใช้ Arrow Function เพื่อส่ง `postId` ไปยัง `fetchPostById` * **`enabled: !!postId`:** นี่คือ Option ที่สำคัญมาก\! มันบอกให้ `useQuery` จะทำการเรียก `queryFn` ก็ต่อเมื่อ `postId` มีค่าเป็น truthy เท่านั้น (ไม่เป็น `null` หรือ `undefined`) ซึ่งมีประโยชน์มากเมื่อเราอาจจะยังไม่มี `postId` ในตอนเริ่มต้น ----- ### Options ที่มีประโยชน์อื่นๆ `useQuery` มี Options มากมายให้เราปรับแต่งพฤติกรรมได้: * **`staleTime` (number | Infinity):** * กำหนดระยะเวลา (มิลลิวินาที) ที่ข้อมูลจะถือว่า "สด" (fresh) * ภายใน `staleTime`, React Query จะไม่ทำการ fetch ข้อมูลใหม่ * ค่าเริ่มต้นคือ `0` (ข้อมูลจะถือว่า stale ทันทีหลังจาก fetch ครั้งแรก) * ถ้าตั้งค่าเป็น `Infinity` ข้อมูลจะไม่มีวัน stale และจะไม่มีการ refetch โดยอัตโนมัติ * **`cacheTime` (number | Infinity):** * กำหนดระยะเวลา (มิลลิวินาที) ที่ข้อมูลจะถูกเก็บไว้ใน cache หลังจากที่ Query ไม่ถูกใช้งานแล้ว * เมื่อ Query ไม่ถูกใช้งานและ `cacheTime` หมดลง ข้อมูลจะถูก garbage-collected * ค่าเริ่มต้นคือ `5 * 60 * 1000` (5 นาที) * **`refetchOnWindowFocus` (boolean | 'always'):** * กำหนดว่าจะให้ Query ทำการ refetch เมื่อหน้าต่างเบราว์เซอร์กลับมาโฟกัสหรือไม่ * ค่าเริ่มต้นคือ `true` * **`retry` (boolean | number):** * กำหนดว่าจะให้ Query ทำการ retry เมื่อเกิดข้อผิดพลาดในการ fetch หรือไม่ * ค่าเริ่มต้นคือ `3` ครั้ง * ตั้งค่าเป็น `false` เพื่อปิดการ retry * **`onSuccess`, `onError`, `onSettled` (Function):** * Callback functions ที่จะถูกเรียกเมื่อ Query สำเร็จ, มีข้อผิดพลาด หรือไม่ว่าจะสำเร็จหรือมีข้อผิดพลาดก็ตาม * **`select` (Function):** * ใช้สำหรับแปลงหรือเลือกข้อมูลบางส่วนจาก `data` ที่ได้มา ก่อนที่จะส่งคืนให้ Component ```javascript const { data: postTitles } = useQuery({ queryKey: ['posts'], queryFn: fetchPosts, select: (posts) => posts.map(post => post.title), // เลือกแค่ title }); // postTitles จะเป็น array ของ strings ``` ----- ### สรุป `useQuery` ของ TanStack React Query เป็นเครื่องมือที่ทรงพลังและขาดไม่ได้สำหรับการจัดการข้อมูลในแอปพลิเคชัน React สมัยใหม่ มันช่วยลดความซับซ้อนของการจัดการสถานะการโหลด, ข้อผิดพลาด, และการแคชข้อมูล ทำให้คุณสามารถโฟกัสกับการสร้างฟีเจอร์ได้มากขึ้น การทำความเข้าใจ `queryKey` และ `queryFn` รวมถึง Options ต่างๆ จะช่วยให้คุณสามารถใช้ประโยชน์จาก React Query ได้อย่างเต็มที่ และสร้างแอปพลิเคชันที่ตอบสนองได้ดีและมีประสิทธิภาพ ลองนำ `useQuery` ไปใช้ในโปรเจกต์ถัดไปของคุณ แล้วคุณจะเห็นถึงความแตกต่างอย่างแน่นอน\!

0 ความคิดเห็น

Earn money online

รวมเทคหาเงินออนไลย์ - หารวยได้เสริม

Is the Designer Facing Extinction?
เล่นเกมส์แล้วไปได้เงิน Rollercoin: เกมจำลองการขุดบิทคอยน์ที่สนุกและคุ้มค่า
คอนเซ็ปต์รายได้จากการดูวิดีโอ