본문 바로가기
프론트엔드/etc

SWR2

by Hyeon_E 2023. 10. 25.

자동갱신

포커스 시에 갱신

페이지내에 다시 포커스하거나 탭을 전환할때 SWR은 자동으로 데이터를 갱신함

최신 상태로 즉시 동기화하라 수 있어 유용함

이 기능은 기본적으로 활성되어 있으나 revalidateOnFocus 옵션을 통해 이를 비활성화 할 수 있음

 

인터벌 시에 갱신

SWR은 자동 데이터 다시 가져오기 옵션을 제공하여 hook과 관련된 컴포넌트가 화면상에 있을 때만 다시 가져옴

refreshInterval 값을 설정하여 활성화할 수 있습니다.

useSWR('/api/todos', fetcher, { refreshInterval: 1000 })

 

refreshWhenHidden, refreshWhenOffline과 같은 옵션도 있음

위에 두 옵션은 기본적으로 비활성이므로 SWR은 웹 페이지가 화면상에 있지 않거나 네트워크 연결이 없으면 가져오기를 하지 않음

 

재연결 시에 갱신

리소스가 불변할경우 다시 갱신해도 변경되지 않음 이러한 경우를 대비해 모든 종류의 자동갱신을 비활성화 할 수 있음

SWR 1.0버전부터 리소스가 불변함을 표시할 수 있드록 useSWRImmutable 헬퍼 hook을 제공함

일반적인 useSWR hook과 동일한 API 인터페이스를 갖고 있음

import useSWRImmutable from 'swr/immutable'
 
// ...
useSWRImmutable(key, fetcher, options)

 

또한 useSWR의 옵션을 이용하여 useSWRImmutable(key, fetcher)를 동일한 작업을 수행할 수 있음

useSWR(key, fetcher, {
  revalidateIfStale: false,
  revalidateOnFocus: false,
  revalidateOnReconnect: false
})
 
// 다음과 동일
useSWRImmutable(key, fetcher)

데이터가 캐시 되면 절대 다시 요청하지 않음

 

뮤테이션(Mutation) & 재검증(Revalidation)

mutate

mutate API를 사용하여 데이터를 변경하는 방법에는 모든 키를 변경할 수 있는 global mutate API와 SWR hook의 데이터만 변경할 수 있는 bound mutate API가 있음

 

Global Mutate

SWR 공식문서에서 global mutator를 가져오는 권장방법은 sueSWRConfig hook을 사용하는 것

import { useSWRConfig } from "swr"
 
function App() {
  const { mutate } = useSWRConfig()
  mutate(key, data, options)
}

전역으로 가져올 수도 있음

import { mutate } from "swr"
 
function App() {
  mutate(key, data, options)
}

 

key 매개변수만 있는 global mutator를 사용하면 동일한 키를 사용하는 마운트 된 SWR hook이 없는 한 캐시를 업데이트하거나 재검증을 트리거 하지 않음

 

Bound Mutate

Bound mutate는 현재 키를 기반으로 데이터로 변경하는 빠른 방법

useSWR 함수에 전달된 키와 연결된 키는 캐시에서 데이터를 찾을 때 사용되며 이렇게 찾은 데이터는 첫 번째 인자로 반환

이전 섹션의 global mutate 함수와 기능적으로 동일하지만 key 매개변수가 필요하지 않음

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()
        // API에 대한 요청을 종료하여 데이터를 업데이트
        await requestUpdateUsername(newName)
        // 로컬 데이터를 즉시 업데이트 하고 다시 유효성 검사(refetch)
        // NOTE: key는 미리 바인딩되어 있으므로 useSWR의 mutate를 사용할 때 필요하지 않음
        mutate({ ...data, name: newName })
      }}>Uppercase my name!</button>
    </div>
  )
}

 

재검증

데이터 없이 mutate(key) (또는 바인딩된 mutate API로 mutate())를 호출하면 리소스에 대한 재검증(데이터를 만료된 것으로 표시하고 refetch를 트리거)을 함

import useSWR, { useSWRConfig } from 'swr'
 
function App () {
  const { mutate } = useSWRConfig()
 
  return (
    <div>
      <Profile />
      <button onClick={() => {
        // 쿠키를 만료된 것으로 설정
        document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
 
        // `/api/user` 라는 키를 가진 모든 SWR에게 재검증을 지시합니다.
        mutate('/api/user')
      }}>
        Logout
      </button>
    </div>
  )
}

위 예제는 사용자가 "로그아웃" 버튼을 클릭할 때 로그인 정보(예: <Profile /> 내부)를 자동으로 다시 가져오는 방법을 보여줌

 

API

매개변수

  • key: useSWR의 key와 동일하지만 함수가 필터 함수처럼 작동
  • data: 데이터를 사용하여 클라이언트 캐시를 업데이트 하거나 클라이언트에서 서버로 데이터를 보내 서버에서 데이터를 변경하는 작업(remote mutation)을 위한 비동기 함수를 사용할 수 있음
  • options: 다음 옵션을 허용함
    • optimisticData: 데이터를 즉시 업데이트 하는 함수 또는 현재 데이터를 수신하여 새 클라이언트 캐시를 반환하는 함수로 일반적으로 optimistic UI에서 사용
    • revalidate = true: 비동기 업데이트가 완료되면 캐시의 유효성을 다시 검사하는 데 사용
    • populateCache = true: remote mutation 결과를 캐시에 기록하거나, 새 결과와 현재 결과를 인자로 받아 mutation 결과를 반환하는 함수를 호출할 수 있음
    • rollbackOnError = true: remote mutation 과정에서 오류가 발생하면 캐시를 롤백해야 하는지 fetcher에서 던져진 오류를 인자로 받아 롤백할지에 대한 여부를 boolean으로 반환하는 함수를 지정할 수 있음
    • throwOnError = true: 호출이 실패했을 때 오류를 발생시킬 수 있음

 

반환 값

mutate는 데이터 매개변수가 해결된 결과를 반환함

변경하기 위해 전달된 함수는 해당 캐시 값을 업데이트 하는 데 사용되는 업데이트 된 데이터를 반환함

함수를 실행하는 동안 에러가 발생하면 적절하게 처리할 수 있도록 에러가 발생함

try {
  const user = await mutate('/api/user', updateUser(newUser))
} catch (error) {
  // 여기에서 사용자를 업데이트 하는 동안 발생한 오류를 처리
}

 

기본 사용법

import useSWRMutation from 'swr/mutation'
 
async function sendRequest(url, { arg }: { arg: { username: string } }) {
  return fetch(url, {
    method: 'POST',
    body: JSON.stringify(arg)
  }).then(res => res.json())
}
 
function App() {
  const { trigger, isMutating } = useSWRMutation('/api/user', sendRequest, /* options */)
 
  return (
    <button
      disabled={isMutating}
      onClick={async () => {
        try {
          const result = await trigger({ username: 'johndoe' }, /* options */)
        } catch (e) {
          // 에러 핸들링
        }
      }}
    >
      Create User
    </button>
  )
}

렌더링에 mutation 결과를 사용하려면 useSWRMutation의 반환 값에서 결과를 가져올 수 있음

const { trigger, data, error } = useSWRMutation('/api/user', sendRequest)

useSWRMutation은 useSWR과 캐시 저장소를 공유하므로 useSWR 간의 경합 조건을 감지하고 피할 수 있음

또한 optimistic update 및 오류 발생 시 롤백과 같은 mutate의 기능도 지원함

이러한 옵션은 useSWRMutation과 트리거 함수를 통해 전달할 수 있음

const { trigger } = useSWRMutation('/api/user', updateUser, {
  optimisticData: current => ({ ...current, name: newName })
})
 
// 또는
 
trigger(newName, {
  optimisticData: current => ({ ...current, name: newName })
})

'프론트엔드 > etc' 카테고리의 다른 글

CSS in JS  (0) 2024.01.12
프론트 배포 실습2  (0) 2023.12.28
프론트 배포 실습  (3) 2023.10.30
프론트 배포 이론  (0) 2023.10.28
SWR  (1) 2023.10.25

댓글