มาลองใช้ SWR เพื่อ Fetch API กันดีกว่า
สวัสดีครับ วันนี้ผมมาลองทำ Example Project ด้วยการลองใช้งาน SWR นะครับ โดยปกิแล้ว เวลาเรา Fetch API จาก Server เราจะใช้พวก native fetch
ที่มากับ Browser หรือบางคนใช้ polifill unfetch
หรือ axios อะไรก็ว่าไป
Link Youtube : https://www.youtube.com/watch?v=skXE8G6AV2Y
ทีนี้ บทความนี้ ผมมาแนะนำ Library ตัวนึงชื่อว่า swr
ครับ และเป็นกึ่งๆ สรุปหัวข้อครับ อาจจะไม่ได้มี Demo หรือ Example เหมือนแบบ Video นะครับ
SWR คืออะไร?
มันย่อมาจาก Stale While Revalidate หากใครคุ้นเคย มันจะเหมือนกับที่เรากำหนด Cache Control ที่ Headers ใช่มั้ย เพราะว่ามันคือการบอกว่าให้โหลดข้อมูลจาก cache ก่อนทำการ fetch api นั่นเอง
ซึ่งวิธีปกติ ถ้าเรา fetch(api)
เราจะยิง request ไปหา Server แต่ถ้า เรา มี cache เราก็ไม่ต้องเสียเวลาไปยิง ก็ได้ข้อมูลมาเลย หรือเราอาจจะเอาข้อมูลจาก cache มาแสดงก่อน แล้วถึง ยิง request ไป เมื่อได้ response กลับมา ถึงมาอัพเดท ค่าเก่า ก็ทำให้ User ไม่ต้องรอ response นั่นเอง
ฉะนั้นสรุปสิ่งที่ SWR ทำคือ
- ทำการดึง data จาก cache มาให้เราก่อน (stale)
- จากนั้นก็ ยิง request ไปที่ API (revalidate)
- นำข้อมูลจาก API ที่ได้มาอัพเดทกับข้อมูลเดิม
อ่านเพิ่มเติมได้ที่นี่เลยครับ https://swr.now.sh/
Basic Data Loading
ก่อนใช้งานก็ติดตั้งปกติครับ
npm install swr
จากนั้นโค๊ดด้านล่างคือ
import useSWR from 'swr'
function Profile () {
const { data, error } = useSWR('/api/user', fetch)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
สิ่งที่ useSWR
ทำคือ รับ parameter เป็น key และ fetcher ที่เป็น function ดังนั้น จะเห็นว่า ค่า argument ที่เราส่งไปคือ api/user
เป็น key และ fetch
เป็น fetcher function นั่งเอง
response กลับมาคือ data
และ error
กรณีที่มี error หรือ 400, 500 หรือ throw error ต่างๆ
Fetcher
Fetcher เป็นแค่ function ที่รับ key หรือ object แล้ว return Promise กลับไป ฉะนั้นตัว fetcher เราจะใช้พวก fetch API ธรมดา หรือ unfetch, isomophic-fetch, request หรือ axios ก็ได้ แล้วแต่เราเลย เช่นใช้ Native Fetch API
const fetcher = key => fetch(key).then(res => res.json())
หรือจะใช้ axios ก็ได้เช่น
import axios from 'axios'
const fetcher = (...args) => axios(...args).then(res => res.data)
SWR Options
ต่อมาคือการที่เราสามารถใส่ Option ลงไปได้ เช่น
const options = {
fetchInterval: 1000
}
const { data, error } = useSWR('/api/user', fetch, options);
ตัว SWR มันจะทำการ Polling data ให้เรา คือการ fetch ทุกๆ 1 วินาทีนั่นเอง หรือแม้แต่จะ revalidateOnFocus
(default คือ true) มันจะทำการ revalidate ทุกครั้งที่ browser นั้น focus แบบสลับแท็ปกลับมาไรงี้ ส่วน Options อื่นๆ มีอีกหลายตัวเลย สามารถอ่านเพิ่มเติมได้จาก Documentation ของ swr ได้เลยครับ https://github.com/zeit/swr
Global Config
ตัว SWR เราสามารถทำ Config แบบ global ที่เดียวก็ได้ เป็น Provider ครอบ component ของเราได้เลย เช่น
import { SWRConfig } from 'swr'
const fetcher = (...args) => fetch(...args).then(res => res.json())
function App () {
return (
<SWRConfig
value={{
refreshInterval: 3000,
fetcher
}}
>
<MyApp />
</SWRConfig>
)
}
Mutate
กรณีที่เราต้องการ ให้ผู้ใช้งานรู้สึกว่าไม่ต้องรอ หรือเห็นผลเลย จากการเปลี่ยนแปลงค่า เช่น อัพเดท Profile แก้ไขค่าอะไรก็แล้วแต่ เราสามารถใช้ local state ได้ โดยใช้ mutate
นั่นเอง ตัวนี้ swr จะแสดง local state ก่อน จากนั้นถึง ส่งข้อมูลไปที่ API จริงๆ จากนั้น ค่อยเอาผลลัพธ์กลับมาอัพเดท หรือแสดงผล
การใช้งานก็คล้ายๆ useSWR
ครับ เช่น
import useSWR from 'swr'
function Profile () {
const { data, mutate } = useSWR('/api/user', fetcher)
return (
<div>
<h1>My name is {data.name}.</h1>
<button onClick={async () => {
const newName = data.name.toUpperCase()
// send a request to the API to update the data
await requestUpdateUsername(newName)
// update the local data immediately and revalidate (refetch)
// NOTE: key is not required when using useSWR's mutate as it's pre-bound
mutate({ ...data, name: newName })
}}>Uppercase my name!</button>
</div>
)
}
โค๊ดนี้จาก SWR Doc คือ กรณีเรา send request เพื่อ PUT/PATCH ไปที่ API แต่ไม่ต้องรอผลลัพธ์ เราสามารพสั่ง mutate
เพื่ออัพเดทค่า data
ที่ได้ตอน fetch ทีแรกได้เลย เพื่อทำการ อัพเดท local data และ revalidate ค่าครับ
สรุป
จะเห็นได้ว่าบทความนี้ ผมแค่ยกตัวอย่างคร่าวๆ มาให้ดูเป็น Overview และโค๊ดส่วนใหญ่ ก็สามารถหาอ่าน ได้จาก README ของ SWR เองอยู่แล้ว หากได้ลองใช้แล้ว ก็ทำให้เราไม่ต้องมาใช้ useEffect()
เพื่อ fetch ข้อมูล หรือจัดการพวก local state, จัดการ state หรือ side effect ต่างๆ มากนัก และมันก็ยังเหมาะกับ Next.js อีกด้วย
ยังไง หากเพื่อนๆ พี่ๆน้องๆ คนไหนยังไม่เคยลองใช้งาน ก็ลองเอาไปใช้งานดูก็ได้นะครับ และหากใครติดปัญหาตรงไหน หรือว่ายังไม่เห็นข้อดี หรือคิดว่าบทความยังไม่ค่อยเข้าใจ สามารถดูเวอร์ชั่น Video Youtube ได้ จาก Link ที่ต้นบทความที่โพสไว้นะครับ
หากติดปัญหา ตรงไหน สอบถาม หรือมีข้อเสนอแนะ ยินดีมากครับ ขอบคุณครับ
Happy Coding ❤️
- Authors
- Name
- Chai Phonbopit
- Website
- @Phonbopit