PALO IT Blog

การใช้ useMutation from React Query

Written by Neung Viriyadamrongkij | 28/02/24

คำนำ

โปรแกรมเมอร์หลายๆ ท่านน่าจะเคยพบปัญหาเรื่อง useMutation หลังใช้งานไปสักพักว่าแบบไหนคือรูปแบบที่ถูกต้องสำหรับเวลานำไปใช้งาน เพราะว่า React Query ก็ค่อนข้างหยืดหยุ่น เปิดโอกาสให้ผู้ใช้สามารถใช้งานได้หลายรูปแบบ 

Q1: ทำไมเราถึงควรใช้ Axios + React Query มากกว่าการใช้งาน Axios อย่างเดียว ? 

Request State Tracking 

ถ้าดูจากรูปภาพด้านบนจะเห็นว่า useMutation ได้เตรียมตัวแปรที่เราสามารถเรียกใช้งานได้ในการ Tracking State ตัวอย่างเช่น isLoading ที่เราสามารถใช้ในการแสดงผลของ Loading Indicator และมันยัง Update แบบ Realtime ด้วย เราจึงไม่จำเป็นต้องทำการจัดการโดยใช้ useState เลย 

Mutation Lifecycle 

useMutation ได้มี Lifecycle ในแต่ละช่วงจังหวะของการ Call API ตั้งแต่ step ก่อนเริ่มยันจบ เราสามารถใช้งาน Callback เหล่านี้ในการ Handle Case ต่าง ๆ ได้มากมาย เช่นการทำ Optimistic update 

Q2: POST Request ควรใช้งานกับ useQuery หรือ useMutation? 

ความเข้าใจผิดของคนส่วนมากคือคิดว่า Post Request ต้องใช้งานกับ useMutation เท่านั้น แต่จริง ๆ เราสามารถใช้งานกับ useQuery ได้เช่นกัน  โดยหลักการคือถ้าเวลาเราเรียก API แล้ว มันเป็นแค่การ Fetch ข้อมูลเฉย ๆ ไม่ได้ทำการแก้ไขข้อมูลใด ๆ ที่ Server กรณีนี้เราควรใช้ useQuery (โดยไม่ต้องคำนึงถึงว่ามันคือ GET หรือ POST) 

สิ่งต่าง ๆ ที่ควรรู้เวลาใช้งาน useMutation

การ mutations ข้อมูลจาก queries 
ในบางครั้งเราสามารถทำการแก้ไขค่าข้อมูลที่เราได้ทำการ Cache มาก่อนหน้านี้ได้ โดยการแก้ไขค่า จะมีอยู่ 2 วิธี 

  1. Invalidation 

    จากตัวอย่างด้านบนมีการใช้งาน useQuery()  ที่เป็น Custom Hook อยู่และ Reuse ใช้ใน 3 Components ซึ่งกรณีเราต้องการ Fetch ข้อมูลใหม่ เราสามารถใช้งาน refrech() ได้ แต่ในกรณีข้างบนการใช้งาน refetch() ไม่ใช้วิธีที่ถูกต้อง เพราะเราต้อง Contain Logic ในการ refetch() ทั้ง 3 Componentes เลย 

    กรณีถ้าเรารู้อยู่แล้วว่าหลังจากที่เรา Add ข้อมูลบางอย่างลงใน DB เสร็จ เราต้องการให้useQeury()ที่เรามีการ Cache ข้อมูลไว้ Reset เราสามารถใช้คำสั่งในการ invalidateQuery() ซึ่งจะทำให้ Code ดู Clean ขึ้น 
  2. Direct updates

    ในบางครั้ง เราไม่ต้องการ Refetch ข้อมูล เพราะว่า Response ที่เราได้รับมามีข้อมูลที่ต้องการใช้ครบถ้วนแล้ว เราสามารถใช้งานคำสั่ง setQueryData() โดยการ Set Value เข้าไปใน queryKey ที่กำหนดได้ 

Awaited Promises 

ถ้าเราต้องการให้ isLoading ยังคงสถานะเป็น loading อยู่จนกว่าinvalidateQueriesจะทำงานเสร็จ เราจะต้องทำการ return Promise ไปด้วยตามตัวอย่างด้านบน 

Mutate or MutateAsync 

กรณีเคสทั่วๆ ไป เราควรใช้งาน mutate() เพราะว่า Function นี้จะมี Life Cycle ต่าง ๆ ที่เราสามารถใช้งานได้ เช่น onSuccess , onErrorเป็นต้น 

กรณีที่ใช้งาน mutateAsync() เราต้องทำการ Handle Error ด้วยตัวเอง และเหมาะกับการใช้ในกรณีที่ เราต้องการ Call หลาย ๆ Mutation พร้อมกันและรอข้อมูลทั้งหมด Return กลับมาก่อนดำเนินการต่อ 

อีกกรณีคือ เราต้องการใช้ Response ที่ได้จาก Request แรกที่เรา Call API เป็น Params ในการเรียก API ตัวถัดไป การใช้งาน mutateAsync() จะช่วยลดการเกิด Callback Hell ได้ 

Some Callbacks Might Not Fire 

โดยปกติแล้ว Callback จะไม่ถูก Trigger ถ้า Component ได้ถูก Unmount ไปก่อนแล้ว 

ถ้าเรามี Logic ที่ถูกใช้งานในลักษณะ Common ไม่ว่า Component ไหนที่เรียก useMutation() นี้ก็จะทำเหมือนกัน (เช่น invalidation) เราควรใส่ Logic นั้นไว้ที่ useMutationCallback 

ถ้าเรามี Logic ในลักษณะเฉพาะ ที่เกี่ยวข้องกับ UI เช่นการ Redirect หรือการแสดง Notification เราควรใส่ไว้ที่ Mutate Callback ของแต่ละ Component 

พูดคุยเกี่ยวกับเรียนรู้การใช้งาน useMutation จาก React Query และเพิ่มประสิทธิภาพในการพัฒนา! ทีม IT Consulting ของเราพร้อมเสนอคำแนะนำที่เหมาะกับธุรกิจของคุณ 

References: 1, 2, 3