Nếu bạn đã từng sử dụng Incremental Static Regeneration (ISR) với Next.js, bạn có thể thấy mình đang gửi dữ liệu cũ đến máy khách. Điều này xảy ra khi bạn đang xác thực lại trang trên máy chủ. Đối với một số trang web, điều này có hiệu quả, nhưng đối với những trang web khác (chẳng hạn như Scrapbook của Hack Club, một trang web do @lachlanjc xây dựng mà tôi giúp duy trì), người dùng mong muốn dữ liệu được cập nhật.
Giải pháp đầu tiên xuất hiện trong đầu có thể chỉ là hiển thị các trang ở phía máy chủ, đảm bảo rằng máy khách luôn được gửi dữ liệu mới nhất. Tuy nhiên, việc truy xuất các khối dữ liệu lớn trước khi hiển thị có thể làm chậm quá trình tải trang ban đầu. Giải pháp được sử dụng trong Scrapbook là sử dụng thư viện SWR của React hooks để cập nhật trang được lưu trong bộ nhớ đệm từ máy chủ bằng cách truy xuất dữ liệu phía máy khách. Phương pháp này đảm bảo rằng người dùng vẫn có trải nghiệm tốt, trang web nhanh và dữ liệu được cập nhật.
Khi được ghép nối với các tuyến API của ISR và Next.js, SWR có thể được sử dụng để tạo trải nghiệm người dùng phản hồi. Đầu tiên, máy khách được phục vụ trang được tạo tĩnh được lưu trong bộ nhớ đệm (được tạo bằng
Bây giờ chúng ta hãy xem lại Scrapbook và cách nó giúp giải quyết vấn đề có dữ liệu cũ trên trang. Điều hiển nhiên là bây giờ, máy khách sẽ nhận được phiên bản cập nhật. Tuy nhiên, điều thú vị hơn là tác động đến tốc độ của phía chúng tôi. Khi chúng tôi đo tốc độ thông qua Lighthouse, chúng tôi nhận được chỉ số tốc độ là 1,5 giây cho biến thể ISR + SWR của trang web và 5,8 giây cho biến thể Server Side Rendering (cộng với cảnh báo về thời gian phản hồi ban đầu của máy chủ). Đây là sự tương phản khá rõ rệt giữa hai biến thể (và điều này cũng đáng chú ý khi tải các trang lên). Nhưng cũng có một sự đánh đổi, trên trang Server Side Rendered, người dùng không thấy bố cục của trang web thay đổi sau vài giây khi có dữ liệu mới. Mặc dù tôi tin rằng Scrapbook xử lý bản cập nhật này tốt, nhưng đây là một cân nhắc quan trọng khi thiết kế trải nghiệm của người dùng.
Tất nhiên, có một số nơi mà bạn sẽ không muốn sử dụng SWR hoặc sử dụng SWR mà không có ISR. SWR không có nhiều tác dụng nếu dữ liệu của bạn không thay đổi hoặc thay đổi rất ít và thay vào đó có thể làm tắc nghẽn các yêu cầu mạng của bạn và sử dụng hết dữ liệu của người dùng thiết bị di động. SWR có thể hoạt động với các trang yêu cầu xác thực, tuy nhiên bạn sẽ muốn sử dụng Server Side Rendering trong những trường hợp này chứ không phải Incremental Static Regeneration.
Chúng ta sẽ cần khả năng này để SWR thực hiện việc truy xuất dữ liệu phía máy khách. Cuối cùng, trong tệp frontend của chúng ta, chúng ta sẽ nhập
Không có gì ở đây là duy nhất đối với SWR hoặc ISR, ngoài cấu trúc dự án đã đề cập ở trên. Những thứ đó bắt đầu ngay từ
Tôi muốn tập trung vào khóa revalidate trong đối tượng trả về của chúng ta. Khóa này thực tế cho phép Tạo lại tĩnh gia tăng. Nó cho máy chủ của bạn biết rằng cứ mỗi giây tạo lại trang tĩnh là một tùy chọn khả dụng, sau đó tùy chọn đó sẽ được kích hoạt ở chế độ nền khi khách hàng truy cập trang của bạn. Bạn có thể đọc thêm về Tạo lại tĩnh gia tăng (ISR) tại đây.
Giờ đã đến lúc sử dụng SWR! Trước tiên, hãy nhập nó:
Chúng ta sẽ sử dụng SWR trong hàm React-rendering của mình, vì vậy hãy tạo hàm đó:
Chúng ta đang nhận các props từ
Chúng ta hãy phân tích điều này. Trước tiên, chúng ta định nghĩa fetcher. SWR yêu cầu điều này như một đối số để biết cách lấy dữ liệu của bạn khi các khung khác nhau, v.v. có thể có các thiết lập khác nhau. Trong trường hợp này, tôi đang sử dụng hàm được cung cấp trên trang tài liệu SWR. Sau đó, chúng tôi gọi hook
Trong đối tượng
Để kết thúc, chúng ta sẽ kết xuất dữ liệu đó bằng một số JSX rất cơ bản:
Và chúng ta đã làm được! Ở đây chúng ta có một ví dụ rất cơ bản về việc sử dụng SWR với Tái tạo tĩnh gia tăng. (Nguồn ví dụ của chúng tôi có sẵn tại đây.)
Nếu bạn gặp phải dữ liệu cũ với ISR, bạn biết phải gọi cho ai: SWR.
Giải pháp đầu tiên xuất hiện trong đầu có thể chỉ là hiển thị các trang ở phía máy chủ, đảm bảo rằng máy khách luôn được gửi dữ liệu mới nhất. Tuy nhiên, việc truy xuất các khối dữ liệu lớn trước khi hiển thị có thể làm chậm quá trình tải trang ban đầu. Giải pháp được sử dụng trong Scrapbook là sử dụng thư viện SWR của React hooks để cập nhật trang được lưu trong bộ nhớ đệm từ máy chủ bằng cách truy xuất dữ liệu phía máy khách. Phương pháp này đảm bảo rằng người dùng vẫn có trải nghiệm tốt, trang web nhanh và dữ liệu được cập nhật.
Meet SWR
SWR là thư viện React Hooks do Vercel xây dựng, tên này bắt nguồn từ thuật ngữ stale-while-revalidate. Như tên gọi, máy khách của bạn sẽ được phục vụ dữ liệu cũ/cũ trong khi dữ liệu mới nhất đang được truy xuất (xác thực lại) thông qua SWR ở phía máy khách. SWR không chỉ xác thực lại dữ liệu một lần, tuy nhiên, bạn có thể cấu hình SWR để xác thực lại dữ liệu theo khoảng thời gian, khi tab lấy lại tiêu điểm, khi máy khách kết nối lại với Internet hoặc theo chương trình.Khi được ghép nối với các tuyến API của ISR và Next.js, SWR có thể được sử dụng để tạo trải nghiệm người dùng phản hồi. Đầu tiên, máy khách được phục vụ trang được tạo tĩnh được lưu trong bộ nhớ đệm (được tạo bằng
getStaticProps()
), ở chế độ nền, máy chủ cũng bắt đầu quá trình xác thực lại trang đó (đọc thêm tại đây). Quá trình này có vẻ nhanh đối với máy khách và giờ đây họ có thể thấy tập dữ liệu, tuy nhiên nó có thể hơi lỗi thời. Sau khi trang được tải, một yêu cầu tìm nạp được thực hiện đến tuyến API Next.js của bạn, trả về cùng dữ liệu như dữ liệu được tạo bằng getStaticProps()
. Khi yêu cầu này hoàn tất (giả sử yêu cầu thành công), SWR sẽ cập nhật trang bằng dữ liệu mới này.Bây giờ chúng ta hãy xem lại Scrapbook và cách nó giúp giải quyết vấn đề có dữ liệu cũ trên trang. Điều hiển nhiên là bây giờ, máy khách sẽ nhận được phiên bản cập nhật. Tuy nhiên, điều thú vị hơn là tác động đến tốc độ của phía chúng tôi. Khi chúng tôi đo tốc độ thông qua Lighthouse, chúng tôi nhận được chỉ số tốc độ là 1,5 giây cho biến thể ISR + SWR của trang web và 5,8 giây cho biến thể Server Side Rendering (cộng với cảnh báo về thời gian phản hồi ban đầu của máy chủ). Đây là sự tương phản khá rõ rệt giữa hai biến thể (và điều này cũng đáng chú ý khi tải các trang lên). Nhưng cũng có một sự đánh đổi, trên trang Server Side Rendered, người dùng không thấy bố cục của trang web thay đổi sau vài giây khi có dữ liệu mới. Mặc dù tôi tin rằng Scrapbook xử lý bản cập nhật này tốt, nhưng đây là một cân nhắc quan trọng khi thiết kế trải nghiệm của người dùng.
Nơi sử dụng SWR (và nơi không nên sử dụng)
SWR có thể được áp dụng ở nhiều nơi khác nhau, sau đây là một số danh mục trang web mà SWR sẽ phù hợp:- Các trang web có dữ liệu trực tiếp cần cập nhật với tốc độ nhanh.
Ví dụ về các trang web như vậy là các trang web tỷ số thể thao và theo dõi chuyến bay. Khi xây dựng các trang web này, bạn sẽ muốn sử dụng tùy chọn xác thực lại theo khoảng thời gian với cài đặt khoảng thời gian thấp (từ một đến năm giây). - Các trang web có kiểu nguồn cấp dữ liệu cập nhật hoặc bài đăng cập nhật theo thời gian thực.
Ví dụ điển hình về điều này là các trang tin tức có blog trực tiếp về các sự kiện như bầu cử. Một ví dụ khác cũng là Scrapbook đã đề cập ở trên. Trong trường hợp này, bạn cũng có thể muốn sử dụng tùy chọn xác thực lại theo khoảng thời gian nhưng với cài đặt khoảng thời gian cao hơn (ba mươi đến sáu mươi giây) để tiết kiệm dữ liệu sử dụng và ngăn chặn các lệnh gọi API không cần thiết. - Các trang web có nhiều bản cập nhật dữ liệu thụ động hơn, mà mọi người thường mở ở chế độ nền.
Ví dụ về các trang web này là các trang thời tiết hoặc các trang số ca mắc COVID-19 trong những năm 2020. Các trang này không cập nhật thường xuyên và do đó không cần xác thực lại liên tục hai ví dụ trước. Tuy nhiên, việc cập nhật dữ liệu vẫn sẽ nâng cao trải nghiệm của người dùng. Trong những trường hợp này, tôi khuyên bạn nên xác thực lại ngày tab lấy lại tiêu điểm và ngày máy khách kết nối lại với internet, điều đó có nghĩa là nếu một người lo lắng quay lại vòi nước với hy vọng chỉ có một sự gia tăng nhỏ về các trường hợp COVID, họ sẽ nhận được dữ liệu đó một cách nhanh chóng. - Các trang web có các phần dữ liệu nhỏ mà người dùng có thể tương tác.
Hãy nghĩ đến Nút Đăng ký của Youtube, khi bạn nhấp vào đăng ký, bạn muốn thấy số lượng thay đổi và cảm thấy như mình đã tạo ra sự khác biệt. Trong những trường hợp này, bạn có thể xác thực lại dữ liệu theo chương trình bằng SWR để lấy số lượng mới và cập nhật số lượng hiển thị.
Tất nhiên, có một số nơi mà bạn sẽ không muốn sử dụng SWR hoặc sử dụng SWR mà không có ISR. SWR không có nhiều tác dụng nếu dữ liệu của bạn không thay đổi hoặc thay đổi rất ít và thay vào đó có thể làm tắc nghẽn các yêu cầu mạng của bạn và sử dụng hết dữ liệu của người dùng thiết bị di động. SWR có thể hoạt động với các trang yêu cầu xác thực, tuy nhiên bạn sẽ muốn sử dụng Server Side Rendering trong những trường hợp này chứ không phải Incremental Static Regeneration.
Sử dụng SWR với Next.js và Incremental Static Regeneration
Bây giờ chúng ta đã khám phá lý thuyết của chiến lược này, hãy cùng khám phá cách chúng ta đưa nó vào thực tế. Đối với điều này, chúng ta sẽ xây dựng một trang web hiển thị số lượng taxi có sẵn tại Singapore (nơi tôi sống!) bằng cách sử dụng API này do chính phủ cung cấp.Cấu trúc dự án
Dự án của chúng tôi sẽ hoạt động bằng cách có ba tệp:-
lib/helpers.js
-
pages/index.js
(tệp giao diện người dùng của chúng tôi) -
pages/api/index.js
(tệp API của chúng tôi)
getTaxiData
) sẽ lấy dữ liệu từ API bên ngoài, sau đó trả về dữ liệu theo định dạng phù hợp để chúng tôi sử dụng. Tệp API của chúng ta sẽ nhập hàm đó và sẽ đặt xuất mặc định của nó thành một hàm xử lý sẽ gọi hàm getTaxiData
rồi trả về hàm đó, điều này có nghĩa là gửi yêu cầu GET đến /api
sẽ trả về dữ liệu của chúng ta.Chúng ta sẽ cần khả năng này để SWR thực hiện việc truy xuất dữ liệu phía máy khách. Cuối cùng, trong tệp frontend của chúng ta, chúng ta sẽ nhập
getTaxiData
và sử dụng nó trong getStaticProps
, dữ liệu của nó sẽ được chuyển đến hàm xuất mặc định của tệp frontend của chúng ta, hàm này sẽ hiển thị trang React của chúng ta. Chúng ta thực hiện tất cả những điều này để ngăn chặn việc trùng lặp mã và đảm bảo tính nhất quán trong dữ liệu của chúng ta. Thật dài dòng, chúng ta hãy bắt đầu lập trình ngay bây giờ.Tệp Helpers
Chúng ta sẽ bắt đầu bằng cách tạo hàmgetTaxiData
trong lib/helpers.js
:
Mã:
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}}
Tệp API
Sau đó, chúng ta sẽ xây dựng hàm xử lý trongapi/index.js
cũng như nhập getTaxiData
function:
Mã:
import { getTaxiData } from '../../lib/helpers'export default async function handler(req, res){ res.status(200).json(await getTaxiData())}
index.js
!Tệp Front-End
Điều đầu tiên chúng ta muốn làm là tạo hàmgetStaticProps
! Hàm này sẽ nhập hàm getTaxiData
của chúng ta, sử dụng hàm đó rồi trả về dữ liệu với một số cấu hình bổ sung.
Mã:
export async function getStaticProps(){ const { getTaxiData } = require("../lib/helpers") return { props: (await getTaxiData()), revalidate: 1 }}
Giờ đã đến lúc sử dụng SWR! Trước tiên, hãy nhập nó:
Mã:
import useSWR from 'swr'
Mã:
export default function App(props){}
getStaticProps
. Bây giờ, chúng ta đã sẵn sàng để thiết lập SWR:
Mã:
const fetcher = (...args) => fetch(...args).then(res => res.json())const { data } = useSWR("/api", fetcher, {fallbackData: props, refreshInterval: 30000})
useSWR
, với ba đối số: đường dẫn để lấy dữ liệu từ đó, hàm lấy dữ liệu và sau đó là đối tượng tùy chọn.Trong đối tượng
options
đó, chúng tôi đã chỉ định hai thứ:- Dữ liệu dự phòng;
- Khoảng thời gian mà SWR nên xác thực lại dữ liệu.
getStaticProps
để đảm bảo dữ liệu có thể nhìn thấy ngay từ đầu. Cuối cùng, chúng ta sử dụng giải cấu trúc đối tượng để trích xuất dữ liệu từ hook.Để kết thúc, chúng ta sẽ kết xuất dữ liệu đó bằng một số JSX rất cơ bản:
Mã:
return Tính đến {data.updatedAt}, có {data.taxis} taxi có sẵn tại Singapore!
Nếu bạn gặp phải dữ liệu cũ với ISR, bạn biết phải gọi cho ai: SWR.
Các tài nguyên khác
Đọc thêm
- Giới thiệu về SWR: React Hooks để truy xuất dữ liệu từ xa, Ibrahima Ndaw
- ISR so với DPR: Từ ngữ to tát, Giải thích nhanh, Cassidy Williams
- Kiểu toàn cục so với kiểu cục bộ trong Next.js, Alexander Dubovoj
- Định tuyến phía máy khách trong Next.js, Adebiyi Adedotun Lukman