Next.js의 ISR(증분 정적 재생)과 함께 SWR 반응 후크 사용
게시 됨: 2022-03-10Next.js와 함께 ISR(증분 정적 재생)을 사용한 적이 있다면 클라이언트에 오래된 데이터를 보내는 자신을 발견했을 수 있습니다. 이것은 서버에서 페이지의 유효성을 다시 검사할 때 발생합니다. 일부 웹사이트에서는 이것이 작동하지만 다른 웹사이트(예: @lachlanjc에서 내가 유지 관리를 위해 만든 사이트인 Hack Club의 스크랩북)에서는 사용자가 데이터가 최신 상태로 유지되기를 기대합니다.
가장 먼저 떠오르는 솔루션은 단순히 서버 측에서 페이지를 렌더링하여 클라이언트가 항상 최신 데이터를 받도록 하는 것일 수 있습니다. 그러나 렌더링 전에 큰 데이터 청크를 가져오면 초기 페이지 로드가 느려질 수 있습니다. Scrapbook에서 사용된 솔루션은 React 후크의 SWR 라이브러리를 사용 하여 클라이언트 측 데이터 가져오기로 서버에서 캐시된 페이지를 업데이트하는 것이었습니다. 이 접근 방식은 사용자가 여전히 좋은 경험을 하고 사이트가 빠르며 데이터가 최신 상태로 유지되도록 합니다.
SWR을 만나다
SWR은 Vercel에서 빌드한 React Hooks 라이브러리로, 이름은 stale-while-revalidate라는 용어에서 따왔습니다. 이름에서 알 수 있듯이 클라이언트 측에서 SWR을 통해 최신 데이터를 가져오는(재검증) 동안 클라이언트에는 오래된/오래된 데이터가 제공됩니다. SWR은 데이터의 유효성을 한 번만 재확인하는 것이 아니라 일정 간격으로 데이터 유효성을 재확인하도록 SWR을 구성할 수 있습니다.
ISR 및 Next.js의 API 경로와 함께 사용하면 SWR을 사용하여 반응형 사용자 환경 을 만들 수 있습니다. 클라이언트는 먼저 캐시된 정적으로 생성된 페이지( getStaticProps()
로 생성됨)를 제공하고, 백그라운드에서 서버도 해당 페이지의 유효성을 다시 확인하는 프로세스를 시작합니다(자세한 내용은 여기 참조). 이 프로세스는 클라이언트에게 빠르게 느껴지고 이제 데이터 세트를 볼 수 있지만 터치가 오래된 것일 수 있습니다. 페이지가 로드되면 getStaticProps()
로 생성된 것과 동일한 데이터를 반환하는 Next.js API 경로로 가져오기 요청이 이루어집니다. 이 요청이 완료되면(성공했다고 가정) SWR은 이 새 데이터로 페이지를 업데이트합니다.
이제 스크랩북을 다시 살펴보고 이것이 페이지에 오래된 데이터가 있는 문제를 해결하는 데 어떻게 도움이 되었는지 살펴보겠습니다. 분명한 것은 이제 클라이언트가 업데이트된 버전을 얻는다는 것입니다. 그러나 더 흥미로운 것은 우리 측의 속도에 미치는 영향입니다. Lighthouse를 통해 속도를 측정할 때 사이트의 ISR + SWR 변형에 대해 1.5초 , Server Side Rendering 변형에 대해 5.8초의 속도 지수(초기 서버 응답 시간에 대한 경고 포함)를 얻습니다. 이것은 둘 사이의 매우 뚜렷한 대조입니다(페이지를 로드할 때도 눈에 띄었습니다). 그러나 Server Side Rendered 페이지에서 새로운 데이터가 들어오는 몇 초 후에 사용자가 사이트 레이아웃을 변경하지 않는다는 절충안도 있습니다. Scrapbook이 이 업데이트를 잘 처리한다고 생각하지만 사용자 경험을 디자인합니다.
SWR을 사용하는 위치(및 사용하지 않는 위치)
SWR은 다양한 장소에 배치할 수 있습니다. 다음은 SWR이 적합할 몇 가지 사이트 범주입니다.
- 빠른 속도로 업데이트해야 하는 라이브 데이터가 있는 사이트.
이러한 사이트의 예로는 스포츠 경기 기록 사이트 및 비행 추적이 있습니다. 이러한 사이트를 구축할 때 낮은 간격 설정(1~5초)과 함께 간격 재검증 옵션을 사용하는 것이 좋습니다. - 실시간으로 업데이트되는 업데이트 또는 게시물의 피드 스타일이 있는 사이트.
이것의 전형적인 예는 선거와 같은 이벤트의 라이브 블로그가 있는 뉴스 사이트일 것입니다. 또 다른 예로 앞서 언급한 스크랩북도 있습니다. 이 경우 데이터 사용량을 절약하고 불필요한 API 호출을 방지하기 위해 더 높은 간격 설정(30~60초)을 사용하여 간격 재검증 옵션을 사용할 수도 있습니다. - 사람들이 백그라운드에서 많이 열어 두는 수동적인 데이터 업데이트가 있는 사이트.
이러한 사이트의 예로는 날씨 페이지 또는 2020년대 COVID-19 사례 번호 페이지가 있습니다. 이러한 페이지는 자주 업데이트되지 않으므로 앞의 두 예를 지속적으로 재확인할 필요가 없습니다. 그러나 업데이트할 데이터에 대한 사용자 경험은 여전히 향상됩니다. 이러한 경우 탭이 다시 포커스를 회복하고 클라이언트가 인터넷에 다시 연결될 때 날짜를 다시 확인하는 것이 좋습니다. 즉, COVID 사례가 약간만 증가하기를 바라면서 초조하게 탭으로 돌아온 사람이 의미합니다. 그 데이터를 빨리 얻으십시오. - 사용자가 상호 작용할 수 있는 작은 데이터 조각이 있는 사이트.
Youtube 구독 버튼을 생각해보세요. 구독을 클릭하면 개수가 변경되는 것을 보고 변화를 만든 것처럼 느껴집니다. 이러한 경우 SWR을 사용하여 프로그래밍 방식으로 데이터의 유효성을 다시 검사하여 새 카운트를 가져오고 표시된 양을 업데이트할 수 있습니다.
한 가지 주의할 점은 이 모든 것이 ISR의 유무에 관계없이 적용될 수 있다는 것입니다.
물론 SWR을 사용하고 싶지 않거나 ISR 없이 SWR을 사용하고 싶지 않은 곳이 있습니다. 데이터가 변경되지 않거나 매우 드물게 변경되는 경우 SWR은 그다지 사용되지 않으며 대신 네트워크 요청을 방해하고 모바일 사용자의 데이터를 사용할 수 있습니다. SWR은 인증이 필요한 페이지에서 작동할 수 있지만 이러한 경우에는 증분 정적 재생이 아닌 서버 측 렌더링을 사용하는 것이 좋습니다.
Next.js 및 증분 정적 재생과 함께 SWR 사용
이제 우리는 이 전략의 이론을 살펴보았고, 이를 실제로 적용하는 방법을 살펴보겠습니다. 이를 위해 정부에서 제공하는 이 API를 사용하여 싱가포르(제가 살고 있는 곳)에서 얼마나 많은 택시를 이용할 수 있는지 보여주는 웹사이트를 구축할 것입니다.
프로젝트 구조
우리 프로젝트는 세 개의 파일로 작동합니다:
-
lib/helpers.js
-
pages/index.js
(프론트엔드 파일) -
pages/api/index.js
(API 파일)
우리의 도우미 파일은 외부 API에서 데이터를 가져올 함수( getTaxiData
)를 내보낸 다음 우리가 사용하기에 적절한 형식으로 반환합니다. API 파일은 해당 함수를 가져오고 getTaxiData
함수를 호출한 다음 반환하는 핸들러 함수로 기본 내보내기를 설정합니다. 즉, /api
에 GET 요청을 보내면 데이터가 반환됩니다.
SWR이 클라이언트 측 데이터 가져오기를 수행하려면 이 기능이 필요합니다. 마지막으로 프론트엔드 파일에서 getStaticProps
getTaxiData
사용할 것입니다. 이 데이터는 React 페이지를 렌더링할 프론트엔드 파일의 기본 내보내기 기능으로 전달됩니다. 우리는 코드 중복을 방지하고 데이터의 일관성을 보장하기 위해 이 모든 작업을 수행합니다. 한입 가득, 이제 프로그래밍을 시작하겠습니다.
도우미 파일
lib/helpers.js
에 getTaxiData
함수를 만드는 것으로 시작하겠습니다.
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 } }
반환된 객체의 revalidate 키에 초점을 맞추고 싶습니다. 이 키는 실질적으로 증분 정적 재생을 활성화합니다. 정적 페이지를 재생성하는 매 1초가 사용 가능한 옵션임을 호스트에 알리고 클라이언트가 페이지를 방문할 때 해당 옵션이 백그라운드에서 트리거됩니다. ISR(증분식 정적 재생)에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
이제 SWR을 사용할 시간입니다! 먼저 임포트하자:
import useSWR from 'swr'
React-rendering 함수에서 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})
이것을 분해해 봅시다. 먼저 fetcher를 정의합니다. 이것은 다른 프레임워크 등이 다른 설정을 가질 수 있다는 점에서 데이터를 가져오는 방법을 알기 위해 SWR에서 인수로 필요합니다. 이 경우 SWR 문서 페이지에서 제공하는 기능을 사용하고 있습니다. 그런 다음 세 가지 인수를 사용하여 useSWR
후크를 호출합니다. 데이터를 가져올 경로, 가져오기 함수 및 옵션 개체입니다.
해당 options
개체에서 두 가지를 지정했습니다.
- 대체 데이터;
- SWR이 데이터를 재검증해야 하는 간격입니다.
대체 데이터 옵션은 데이터가 처음부터 표시되도록 하는 getStaticProps
에서 가져온 데이터를 제공하는 곳입니다. 마지막으로 객체 구조화를 사용하여 후크에서 데이터를 추출합니다.
마무리를 위해 매우 기본적인 JSX로 해당 데이터를 렌더링합니다.
return <div>As of {data.updatedAt}, there are {data.taxis} taxis available in Singapore!</div>
그리고 우리는 해냈습니다! 증분 정적 재생과 함께 SWR을 사용하는 아주 기본적인 예가 있습니다. (예제 소스는 여기에서 볼 수 있습니다.)
ISR에서 오래된 데이터를 만난 적이 있다면 누구에게 전화해야 하는지 알 수 있습니다. SWR.
SmashingMag에 대한 추가 정보
- SWR React Hooks 라이브러리
- SWR 소개: 원격 데이터 가져오기를 위한 React Hooks, Ibrahima Ndaw
- ISR 대 DPR: 큰 단어, 빠른 설명, Cassidy Williams
- Next.js의 글로벌 대 로컬 스타일링, Alexander Dubovoj
- Next.js의 클라이언트 측 라우팅, Adebiyi Adedotun Lukman