การใช้ SWR React Hooks กับ Incremental Static Regeneration (ISR) ที่เพิ่มขึ้นของ Next.js
เผยแพร่แล้ว: 2022-03-10หากคุณเคยใช้ Incremental Static Regeneration (ISR) กับ Next.js คุณอาจพบว่าตัวเองกำลังส่งข้อมูลเก่าไปยังไคลเอนต์ สิ่งนี้เกิดขึ้นเมื่อคุณกำลังตรวจสอบหน้าบนเซิร์ฟเวอร์อีกครั้ง สำหรับบางเว็บไซต์ก็ใช้งานได้ แต่สำหรับเว็บไซต์อื่นๆ (เช่น Hack Club's Scrapbook ซึ่งเป็นไซต์ที่สร้างโดย @lachlanjc ที่ฉันช่วยดูแล) ผู้ใช้คาดหวังว่าข้อมูลจะได้รับการอัปเดตอยู่เสมอ
วิธีแก้ปัญหาแรกที่นึกถึงอาจเป็นแค่การแสดงหน้าเว็บในฝั่งเซิร์ฟเวอร์ เพื่อให้มั่นใจว่าไคลเอ็นต์จะส่งข้อมูลที่ทันสมัยที่สุดเสมอ อย่างไรก็ตาม การดึงข้อมูลจำนวนมากก่อนแสดงผลอาจทำให้การโหลดหน้าแรกช้าลง วิธีแก้ปัญหาที่ใช้ใน Scrapbook คือการใช้ไลบรารี SWR ของ React hooks เพื่อ อัปเดตหน้าที่แคชจากเซิร์ฟเวอร์ด้วยการดึงข้อมูลฝั่งไคลเอ็นต์ แนวทางนี้ช่วยให้แน่ใจว่าผู้ใช้ยังคงได้รับประสบการณ์ที่ดี ไซต์นั้นรวดเร็ว และข้อมูลจะได้รับการอัปเดตอยู่เสมอ
พบกับSWR
SWR เป็นไลบรารี React Hooks ที่สร้างโดย Vercel ชื่อนี้มาจากคำว่า stale-while-revalidate ตามชื่อที่แนะนำ ลูกค้าของคุณจะได้รับข้อมูลเก่า/เก่าในขณะที่ข้อมูลล่าสุดกำลังถูกดึง (ตรวจสอบอีกครั้ง) ผ่าน SWR ทางฝั่งไคลเอ็นต์ SWR ไม่ได้ตรวจสอบความถูกต้องของข้อมูลเพียงครั้งเดียว อย่างไรก็ตาม คุณสามารถกำหนดค่า SWR ให้ตรวจสอบข้อมูลอีกครั้งในช่วงเวลาหนึ่ง เมื่อแท็บกลับมาโฟกัสอีกครั้ง เมื่อไคลเอ็นต์เชื่อมต่อกับอินเทอร์เน็ตอีกครั้งหรือโดยทางโปรแกรม
เมื่อจับคู่กับเส้นทาง API ของ ISR และ Next.js คุณสามารถใช้ SWR เพื่อสร้าง ประสบการณ์ผู้ใช้ ที่ตอบสนองได้ ไคลเอนต์จะได้รับหน้าที่แคชที่สร้างขึ้นแบบสแตติกก่อน (สร้างด้วย getStaticProps()
) ในพื้นหลัง เซิร์ฟเวอร์จะเริ่มกระบวนการตรวจสอบหน้านั้นอีกครั้ง (อ่านเพิ่มเติมที่นี่) กระบวนการนี้ทำให้ลูกค้ารู้สึกรวดเร็ว และตอนนี้พวกเขาสามารถเห็นชุดข้อมูลได้ อย่างไรก็ตาม มันอาจจะดูไม่ทันสมัย เมื่อโหลดหน้าเว็บแล้ว คำขอดึงข้อมูลจะถูกส่งไปยังเส้นทาง Next.js API ของคุณ ซึ่งจะส่งคืนข้อมูลเดียวกันกับที่สร้างขึ้นด้วย getStaticProps()
เมื่อคำขอนี้เสร็จสมบูรณ์ (สมมติว่าสำเร็จ) SWR จะอัปเดตหน้าด้วยข้อมูลใหม่นี้
คราวนี้ลองย้อนกลับไปที่สมุดเรื่องที่สนใจและ วิธีนี้ช่วยแก้ปัญหาการมีข้อมูลเก่าบนหน้า ได้อย่างไร สิ่งที่ชัดเจนคือตอนนี้ไคลเอ็นต์ได้รับเวอร์ชันที่อัปเดตแล้ว อย่างไรก็ตาม สิ่งที่น่าสนใจกว่านั้นคือผลกระทบต่อความเร็วของฝั่งเรา เมื่อเราวัดความเร็วผ่าน Lighthouse เราจะได้รับดัชนีความเร็ว 1.5 วินาที สำหรับตัวแปร ISR + SWR ของไซต์ และ 5.8 วินาที สำหรับตัวแปรการแสดงผลฝั่งเซิร์ฟเวอร์ (รวมถึงคำเตือนเกี่ยวกับเวลาตอบสนองเริ่มต้นของเซิร์ฟเวอร์) นั่นเป็นความแตกต่างอย่างสิ้นเชิงระหว่างทั้งสอง (และเห็นได้ชัดเมื่อโหลดหน้าขึ้นเช่นกัน) แต่ก็มีข้อเสียเช่นกัน ในหน้า Server Side Rendered ผู้ใช้ไม่ได้เปลี่ยนเลย์เอาต์ของไซต์หลังจากผ่านไปสองสามวินาทีเมื่อมีข้อมูลใหม่เข้ามา ในขณะที่ฉันเชื่อว่า Scrapbook จัดการกับการอัปเดตนี้ได้ดี การพิจารณาที่สำคัญเมื่อ การออกแบบประสบการณ์ผู้ใช้ของคุณ
จะใช้ SWR ได้ที่ไหน (และไม่ควรใช้)
สามารถใช้ SWR ในสถานที่ต่างๆ ได้ ต่อไปนี้คือหมวดหมู่ไซต์สองประเภทที่ SWR เหมาะสมอย่างยิ่ง:
- ไซต์ที่มีข้อมูลสดที่ต้องการการอัปเดตอย่างรวดเร็ว
ตัวอย่างของไซต์ดังกล่าว ได้แก่ ไซต์คะแนนกีฬาและการติดตามเที่ยวบิน เมื่อสร้างไซต์เหล่านี้ คุณจะต้องใช้ตัวเลือกการตรวจสอบซ้ำในช่วงเวลาที่มีการตั้งค่าช่วงเวลาต่ำ (หนึ่งถึงห้าวินาที) - ไซต์ที่มีรูปแบบฟีดของการอัปเดตหรือโพสต์ที่อัปเดตแบบเรียลไทม์
ตัวอย่างคลาสสิกของเรื่องนี้คือเว็บไซต์ข่าวที่มีบล็อกสดเกี่ยวกับกิจกรรมต่างๆ เช่น การเลือกตั้ง อีกตัวอย่างหนึ่งก็คือสมุดเรื่องที่สนใจดังกล่าวเช่นกัน ในกรณีนี้ คุณอาจต้องการใช้ตัวเลือกตรวจสอบซ้ำในช่วงเวลา แต่ด้วยการตั้งค่าช่วงเวลาที่สูงขึ้น (สามสิบถึงหกสิบวินาที) เพื่อประหยัดการใช้ข้อมูลและป้องกันการเรียก API ที่ไม่จำเป็น - ไซต์ที่มีการอัปเดตข้อมูลแบบพาสซีฟมากขึ้น ซึ่งผู้คนมักเปิดอยู่เบื้องหลัง
ตัวอย่างของเว็บไซต์เหล่านี้ ได้แก่ หน้าสภาพอากาศหรือในหน้าหมายเลขกรณี COVID-19 ในปี 2020 หน้าเหล่านี้ไม่ได้อัปเดตบ่อยนัก ดังนั้นจึงไม่จำเป็นต้องตรวจสอบสองตัวอย่างก่อนหน้านี้อย่างต่อเนื่อง อย่างไรก็ตาม ข้อมูลจะยังคงปรับปรุงประสบการณ์ผู้ใช้สำหรับการอัปเดตข้อมูล ในกรณีเหล่านี้ ฉันขอแนะนำให้ตรวจสอบวันที่ที่แท็บกลับมาโฟกัสอีกครั้ง และเมื่อลูกค้าเชื่อมต่ออินเทอร์เน็ตอีกครั้ง นั่นจะหมายความว่าหากบุคคลนั้นกลับมาที่ก๊อกอย่างใจจดใจจ่อ หวังว่ากรณีโควิดจะเพิ่มขึ้นเพียงเล็กน้อยเท่านั้น รับข้อมูลนั้นอย่างรวดเร็ว - ไซต์ที่มีข้อมูลเล็กๆ น้อยๆ ที่ผู้ใช้สามารถโต้ตอบได้
ลองนึกถึงปุ่มสมัครรับข้อมูล Youtube เมื่อคุณคลิกสมัครรับข้อมูล คุณต้องการเห็นการเปลี่ยนแปลงจำนวนนั้นและรู้สึกว่าคุณได้สร้างความแตกต่าง ในกรณีเหล่านี้ คุณสามารถตรวจสอบข้อมูลอีกครั้งโดยทางโปรแกรมโดยใช้ SWR เพื่อดึงจำนวนใหม่และอัปเดตจำนวนที่แสดง
สิ่งหนึ่งที่ควรทราบก็คือ สิ่งเหล่านี้สามารถใช้ได้ทั้งแบบมีหรือไม่มี ISR

มีบางแห่งที่คุณไม่ต้องการใช้ SWR หรือใช้ SWR โดยไม่มี ISR SWR จะไม่มีประโยชน์มากนักหากข้อมูลของคุณไม่เปลี่ยนแปลงหรือแทบไม่มีการเปลี่ยนแปลง และสามารถขัดขวางคำขอเครือข่ายของคุณและใช้ข้อมูลของผู้ใช้มือถือได้ SWR สามารถทำงานกับเพจที่ต้องการการรับรองความถูกต้อง อย่างไรก็ตาม คุณจะต้องใช้ Server Side Rendering ในกรณีเหล่านี้ ไม่ใช่ Incremental Static Regeneration
การใช้ SWR กับ Next.js และ Incremental Static Regeneration
ตอนนี้เราได้สำรวจทฤษฎีของกลยุทธ์นี้แล้ว มาสำรวจว่าเรานำมันไปปฏิบัติอย่างไร สำหรับสิ่งนี้ เราจะสร้างเว็บไซต์ที่แสดงจำนวนรถแท็กซี่ในสิงคโปร์ (ที่ฉันอาศัยอยู่!) โดยใช้ API นี้ที่รัฐบาลจัดหาให้
โครงสร้างโครงการ
โครงการของเราจะทำงานโดยมีสามไฟล์:
-
lib/helpers.js
-
pages/index.js
(ไฟล์ส่วนหน้าของเรา) -
pages/api/index.js
(ไฟล์ API ของเรา)
ไฟล์ตัวช่วยของเราจะส่งออกฟังก์ชัน ( getTaxiData
) ที่จะดึงข้อมูลจาก API ภายนอก จากนั้นส่งคืนในรูปแบบที่เหมาะสมสำหรับการใช้งานของเรา ไฟล์ API ของเราจะนำเข้าฟังก์ชันนั้น และจะตั้งค่าการส่งออกเริ่มต้นเป็นฟังก์ชันตัวจัดการที่จะเรียกใช้ฟังก์ชัน getTaxiData
แล้วส่งคืน ซึ่งหมายความว่าการส่งคำขอ GET ไปยัง /api
จะส่งคืนข้อมูลของเรา
เราต้องการความสามารถนี้สำหรับ SWR ในการดึงข้อมูลฝั่งไคลเอ็นต์ สุดท้ายนี้ ในไฟล์ส่วนหน้า เราจะนำเข้า getTaxiData
และใช้ใน getStaticProps
ข้อมูลจะถูกส่งไปยังฟังก์ชันการส่งออกเริ่มต้นของไฟล์ส่วนหน้าซึ่งจะแสดงหน้า React ของเรา เราทำทั้งหมดนี้เพื่อป้องกันการซ้ำซ้อนของโค้ดและรับรองความสอดคล้องในข้อมูลของเรา ช่างเป็นคำพูดที่ดี มาเริ่มเขียนโปรแกรมกันเลยดีกว่า
ไฟล์ Helpers
เราจะเริ่มต้นด้วยการสร้างฟังก์ชัน getTaxiData
ใน lib/helpers.js
:
export async function getTaxiData(){ let data = await fetch("https://api.data.gov.sg/v1/transport/taxi-availability").then(r => r.json()) return {taxis: data.features.properties[0].taxi_count, updatedAt: data.features.properties[0].timestamp} }
ไฟล์ API
จากนั้นเราจะสร้างฟังก์ชันตัวจัดการใน api/index.js
รวมทั้งนำเข้าฟังก์ชัน getTaxiData
:
import { getTaxiData } from '../../lib/helpers' export default async function handler(req, res){ res.status(200).json(await getTaxiData()) }
ไม่มีอะไรพิเศษที่นี่สำหรับ SWR หรือ ISR นอกเหนือจากโครงสร้างโครงการดังกล่าว สิ่งนั้นเริ่มต้นใน index.js
!
ไฟล์ส่วนหน้า
สิ่งแรกที่เราต้องการทำคือสร้างฟังก์ชัน getStaticProps
! ฟังก์ชันนี้จะนำเข้าฟังก์ชัน getTaxiData
ของเรา ใช้งานแล้วส่งคืนข้อมูลพร้อมการกำหนดค่าเพิ่มเติมบางอย่าง
export async function getStaticProps(){ const { getTaxiData } = require("../lib/helpers") return { props: (await getTaxiData()), revalidate: 1 } }
ฉันต้องการเน้นที่คีย์ตรวจสอบซ้ำในวัตถุที่ส่งคืนของเรา คีย์นี้ช่วยให้สามารถสร้าง Incremental Static Regeneration ได้จริง มันบอกโฮสต์ของคุณว่าทุก ๆ หนึ่งวินาทีที่สร้างหน้าสแตติกใหม่นั้นเป็นตัวเลือกที่มี จากนั้นตัวเลือกนั้นจะถูกทริกเกอร์ในพื้นหลังเมื่อลูกค้าเยี่ยมชมเพจของคุณ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ Incremental Static Regeneration (ISR) ได้ที่นี่
ได้เวลาใช้ SWR แล้ว! มานำเข้ากันก่อน:
import useSWR from 'swr'
เรากำลังจะใช้ SWR ในฟังก์ชันการแสดงปฏิกิริยา ดังนั้นมาสร้างฟังก์ชันนั้นกัน:
export default function App(props){ }
เราได้รับอุปกรณ์ประกอบฉากจาก getStaticProps
ตอนนี้เราพร้อมที่จะตั้งค่า SWR แล้ว:
const fetcher = (...args) => fetch(...args).then(res => res.json()) const { data } = useSWR("/api", fetcher, {fallbackData: props, refreshInterval: 30000})
มาทำลายสิ่งนี้กันเถอะ ประการแรก เรากำหนดตัวดึงข้อมูล SWR ต้องการสิ่งนี้เป็นอาร์กิวเมนต์ เพื่อให้รู้วิธีดึงข้อมูลของคุณเนื่องจากเฟรมเวิร์กที่แตกต่างกัน ฯลฯ สามารถมีการตั้งค่าต่างกันได้ ในกรณีนี้ ฉันใช้ฟังก์ชันที่ให้ไว้ในหน้าเอกสาร SWR จากนั้นเราเรียก useSWR
hook โดยมีสามอาร์กิวเมนต์: พาธเพื่อดึงข้อมูลจาก ฟังก์ชัน fetcher และอ็อบเจกต์ options
ในอ็อบเจ็กต์ options
นั้น เราได้ระบุสองสิ่ง:
- ข้อมูลสำรอง;
- ช่วงเวลาที่ SWR ควรตรวจสอบข้อมูลอีกครั้ง
ตัวเลือกข้อมูลทางเลือกเป็นที่ที่เราจัดเตรียมข้อมูลที่ดึงมาจาก getStaticProps
ซึ่งทำให้มั่นใจได้ว่าข้อมูลจะมองเห็นได้ตั้งแต่เริ่มต้น สุดท้ายนี้ เราใช้ object destructuring เพื่อดึงข้อมูลออกจาก hook
ในการดำเนินการให้เสร็จสิ้น เราจะแสดงผลข้อมูลนั้นด้วย JSX ขั้นพื้นฐาน:
return <div>As of {data.updatedAt}, there are {data.taxis} taxis available in Singapore!</div>
และเราทำเสร็จแล้ว! เรามีตัวอย่างง่ายๆ เกี่ยวกับการใช้ SWR กับ Incremental Static Regeneration (แหล่งที่มาของตัวอย่างของเรามีอยู่ที่นี่)
หากคุณพบข้อมูลเก่ากับ ISR คุณจะรู้ว่าควรโทรหาใคร: SWR
อ่านเพิ่มเติมเกี่ยวกับ SmashingMag
- ห้องสมุด SWR React Hooks
- บทนำสู่ SWR: React Hooks สำหรับการดึงข้อมูลระยะไกล Ibrahima Ndaw
- ISR vs DPR: Big Words, Quick Description, แคสสิดี้ วิลเลียมส์
- Global vs. Local Styling ใน Next.js, Alexander Dubovoj
- การกำหนดเส้นทางฝั่งไคลเอ็นต์ใน Next.js, Adebiyi Adedotun Lukman