SWR(stale-while-revalidate)

Je·2023년 3월 24일
0
post-thumbnail

SWR

SWR은 stale-while-revalidate에서 유래되었고, 캐시(stale)로부터 데이터를 반환한 후, fetch 요청(재검증)을 하고, 최종적으로 최신화된 데이터를 가져오는 전략입니다

데이터를 가져오기 위한 React Hooks고 Next.JS를 개발한 zeit 그룹에서 사용하는 라이브러리고, 백그라운드에서 캐시를 재검증(revaildate)하는 동안에 기존의 캐시 데이터(stale)를 사용하여 화면을 그려줍니다 도중에 에러를 반환하더라도 캐시된 데이터를 활용할 수 있게 함으로써 불필요한 데이터 호출과 렌더링에 시간을 쓰지 않고 효율적으로 동작합니다

장점


  • 빠르고, 가볍고, 재사용 가능한 데이터 가져오기
  • 내장된 캐시 및 요청 중복 제거
  • 실시간 경험
  • 전송 및 프로토콜에 구애받지 않음
  • SSR / ISR / SSG support

설치 방법


$ npm i swr

사용 방법


// 일반적 예시
const fetcher = (...args) => fetch(...args).then(res => res.json())

// axios 사용시
import axios from 'axios';

const fetcher = url => axios.get(url).then(res => res.data);

// 실질적 사용 방법
import useSWR from 'swr'
 
function Profile () {
  const { data, error, isLoading } = useSWR('/api/user/123', fetcher)
 
  if (error) return <div>failed to load</div>
  if (isLoading) return <div>loading...</div>
 
  // 데이터 렌더링
  return <div>hello {data.name}!</div>
}

// 재사용 가능하게 만들기 (훅 생성)
function useUser (id) {
  const { data, error, isLoading } = useSWR(`/api/user/${id}`, fetcher)
 
  return {
    user: data,
    isLoading,
    isError: error
  }
}

// 컴포넌트 내부에서 훅 사용
function Avatar ({ id }) {
  const { user, isLoading, isError } = useUser(id)
 
  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return <img src={user.avatar} />
}

API


const { data, error, isLoading, isValidating, mutate } = useSWR(key, fetcher, options)
  • 파라미터
    • key: 요청을 위한 고유한 키 문자열(또는 함수 / 배열 / null) (상세내용)(고급 사용법)
    • fetcher: (옵션) 데이터를 가져오기 위한 함수를 반환하는 Promise (상세내용)
    • options: (옵션) SWR hook을 위한 옵션 객체
  • 반환 값
    • datafetcher가 이행한 주어진 키에 대한 데이터(로드되지 않았다면 undefined)

    • errorfetcher가 던진 에러(또는 undefined)

    • isLoading: 진행 중인 요청이 있고 "로드된 데이터"가 없는 경우. 폴백 데이터와 이전 데이터는 "로드된 데이터"로 간주하지 않습니다.

    • isValidating: 요청이나 갱신 로딩의 여부

    • mutate(data?, options?): 캐시 된 데이터를 뮤테이트하기 위한 함수 (상세내용)

      더 많은 정보는 여기서 확인할 수 있습니다.

  • 옵션
    • suspense = false: React Suspense 모드를 활성화 (상세내용)
    • fetcher(args): fetcher 함수
    • revalidateIfStale = true: 오래된 데이터가 있더라도 자동으로 다시 확인 (상세내용)
    • revalidateOnMount: 컴포넌트가 마운트되었을 때 자동 갱신 활성화 또는 비활성화
    • revalidateOnFocus = true: 창이 포커싱되었을 때 자동 갱신 (상세내용)
    • revalidateOnReconnect = true: 브라우저가 네트워크 연결을 다시 얻었을 때 자동으로 갱신(navigator.onLine을 통해) (상세내용)
    • refreshInterval (상세내용):
      • 기본적으로는 비활성화: refreshInterval = 0
      • number로 설정된 경우, 폴링 인터벌(밀리초)
      • function으로 설정된 경우, 함수가 최신 데이터를 받고 인터벌 반환(밀리초)
    • refreshWhenHidden = false: 창이 보이지 않을 때 폴링(refreshInterval이 활성화된 경우)
    • refreshWhenOffline = false: 브라우저가 오프라인일 때 폴링(navigator.onLine에 의해 결정됨)
    • shouldRetryOnError = true: fetcher에 에러가 있을 때 재시도
    • dedupingInterval = 2000: 이 시간 범위내에 동일 키를 사용하는 요청 중복 제거(밀리초)
    • focusThrottleInterval = 5000: 이 시간 범위 동안 단 한 번만 갱신(밀리초)
    • loadingTimeout = 3000: onLoadingSlow 이벤트를 트리거 하기 위한 타임아웃(밀리초)
    • errorRetryInterval = 5000: 에러 재시도 인터벌(밀리초)
    • errorRetryCount: 최대 에러 재시도 수
    • fallback: 다중 폴백 데이터의 키-값 객체 (예시)
    • fallbackData: 반환될 초기 데이터(노트: hook 별로 존재)
    • keepPreviousData = false: 새 데이터가 로드될 때까지 이전 키의 데이터를 반환 (상세내용)
    • onLoadingSlow(key, config): 요청을 로드하는 데 너무 오래 걸리는 경우의 콜백 함수(loadingTimeout을 보세요)
    • onSuccess(data, key, config): 요청이 성공적으로 종료되었을 경우의 콜백 함수
    • onError(err, key, config): 요청이 에러를 반환했을 경우의 콜백 함수
    • onErrorRetry(err, key, config, revalidate, revalidateOps): 에러 재시도 핸들러
    • onDiscarded(key): 경합 상태(race condition)로 인해 요청이 무시될 경우 실행되는 콜백 함수
    • compare(a, b): 비논리적인 리렌더러를 회피하기 위해 반환된 데이터가 변경되었는지를 감지하는데 사용하는 비교 함수. 기본적으로 stable-hash(opens in a new tab)을 사용합니다.
    • isPaused(): 갱신의 중지 여부를 감지하는 함수. true가 반환될 경우 가져온 데이터와 에러는 무시합니다. 기본적으로는 false를 반환합니다.
    • use: 미들웨어 함수의 배열 (상세내용)

stale-while-revalidate란?


swr 전략은 캐싱된 컨텐츠를 즉시 로드하는 즉시성과 업데이트된 캐싱 컨텐츠가 미래에 사용되도록 보장하기 위핸 디렉티브입니다 브라우저는 Cache-Control의 max-age를 기준으로 캐싱된 컨텐츠의 최신 상태 여부를 판단하게 되는데, swr은 캐싱된 낡은 컨텐츠에 대한 확장된 지시를 표현합니다

Cache-Control: max-age=1, stale-while-revalidate=59
  1. HTTP 요청이 1초(max-age)이내에 반복적으로 발생한다면, 유효성 검증 없이 캐싱된 컨텐츠를 반환합니다

  1. HTTP 요청이 1~60초(max-age ~ swr) 사이에 반복적으로 발생할 경우, 우선 캐싱된 낡은 컨텐츠를 반환하고, 이와 동시에 캐싱된 컨텐츠를 새로운 컨텐츠로 채우도록 재검증 요청이 발생합니다

  1. HTTP 요청이 60초(swr~)이후 시점에 발생한다면, 요청이 서버로 전달되어 컨텐츠를 반환 받습니다.

react-query와 swr


클라이언트에서 리덕스를 사용한다면 서버로부터 전달받은 값을 리덕스에 저자하고 최신화된 데이터로서 사용되지만 특정 시점의 서버 데이터를 캡쳐한 것이고, 이 데이터가 최신화된 데이터라고 보장하기가 어렵습니다

그렇다보니 페이지 전환, 유저의 인터렉션이 새롭게 발생되면 새로운 요청을 리덕스 스토어의 값을 업데이트 해주어야 하는 최신화에 대한 의무와 시점에 대한 고민, 그리고 중복된 디스패치에 대한 제거는 오로지 클라이언트 개발자의 몫이었습니다

반면 react-query, swr은 낡은 캐시로부터 빠르게 컨텐츠를 반환하고, 백그라운드에서 요청을 통해 캐싱된 컨텐츠의 재검증을 진행하여 캐싱 레이어에서 최신화된 데이터를 보장할 수 있도록 swr 캐싱 전략을 취하고 있습니다

출처: https://youthfulhps.dev/web/stale-while-ravalidate/

출처 2: https://velog.io/@soryeongk/SWRBasic

profile
제리 젤리

0개의 댓글