useSWR

kirin.log·2021년 9월 7일
0

🍀 useSWR

  • S(stail) W(while) R(revalidate) = 처음 캐시로부터 데이터를 가져오고(stale), fetch요청을 보내 revalidating하여 최신 데이터를 유지한다.
  • API 데이터를 가져오기 위한 React Hooks 이다. (=Data Fetching 라이브러리)
  • SWR을 사용하여 실시간으로 데이터를 가져오거나 캐싱하거나 다시 가져올 수 있다.
  • SWR의 전략은 캐싱된 데이터가 있으면 먼저 가져오며, 서버 데이터 가져온 후 마지막으로 최신의 데이터를 업데이트한다.

useSWR공식문서

💦 SWR 진행 과정
(1) 먼저 캐시(stale, 스태일)로부터 데이터를 반환한 후 (=cache로 부터 받아온 데이터 즉, 오래된 정보를 먼저 return)
(2) fetch 요청(재검증)을 하고 (=서버에서 데이터 가져오기)
(3) 최종적으로 최신화된 데이터를 가져오는 전략 (=재검증, 마지막으로 최신 데이터 가져오기)

💦 SWR 의 특징

  • Lightweight : 가벼움.
  • Realtime : 자동으로 데이터 업데이트. (실시간 경험)
  • Suspense : 항상 빠르고 반응적.
  • Pagination : 쪽수 매기기
  • Backend Agnostic : Backend에 의존하지 않음.
  • SSR / ISR / SSG 지원
  • TypeScript Ready
  • 내장된 캐시 및 요청 중복 제거

💦 useSWR(첫 번째 인자[key], 두 번째 인자[fetcher](fetch로 받아온 url)) ⭐️⭐️⭐️

{ data, error } = useSWR(key, fetcher)
  • 필요한 인자 📌
    • key
      key는(일반적으로 API Request URL) 데이터의 고유 식별자이며 fetcher로 전달된다.
      = 캐시 키 (null을 반환, 오류를 던지거나, 잘못된 값을 반환하면 useSWR이 가져오기를 수행하지 않는다)
    • fetcher
      데이터를 반환하는 모든 비동기함수, native fetch나 Axios와 같은 도구를 사용할 수 있다.

(1) useSWR 의 첫번째 인자인 key 값을 기준으로 중복 요청을 제거하고, 캐시를 하며, 해당 값을 마치 전역 상태관리처럼 share 까지 해준다.
(2) useSWR 의 두번째 인자인 fetcher 은 SWR 내부적으로 구현되어있는 것이 아니라 사용자가 직접 정의하는 것이다. 때문에 fetch, axios 던 문제 없이 사용 가능하다.

  • return값 📌
    • data
      요청의 반환값으로 재검증 과정에서는 캐시된 데이터를 반환하고, 재검증 이후 새롭게 받은 데이터를 반환한다.
    • error
      fetcher로 반환된 error가 있다면, hook을 통해 error로 반환된다.

🍀 useSWR 사용하여 데이터 fetch / fetch 함수 사용하여 데이터 fetch 비교하기

일반적으로 parent 컴포넌트 에서 data fetch 를 실행한 후 child 컴포넌트 에 props 로 전달하는 형태로 로직이 구성된다.
(만약 전역상태를 관리한다면 fetch 만 top level 에서 하고 child 컴포넌트에서는 주로 사용하는 형태.)

SWR 에서는 사용하는 곳에서 바로 data fetch 를 실행함과 동시에 로컬 스테이트를 정의할 수 있다.

// 기존 fetch로 data를 받아오는 경우----------

// 부모 component에서 데이터를 fetch한다.
function Page () {
  const [user, setUser] = useState(null)

  // fetch data
  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(data => setUser(data))
  }, [])

  // global loading state
  if (!user) {
    return <Spinner/>
  }
  return (
    <div>
      // 자식 컴포넌트로 props넘겨준다
      <Avatar user={user} /> 
      <Content user={user} />
    </div>
  )
}

// child components
function Content ({ user }) {
  return <h1>Welcome back, {user.name}</h1>
}
function Avatar ({ user }) {
  return <img src={user.avatar} alt={user.name} />
}

------------------------------------------------------

// useSWR 로 data를 받아오는 경우----------

❗️ 단 한번의 API request 만 있다.

function useUser (id) {
  const { data, error } = useSWR(`/api/user/${id}`, fetcher)

// API 데이터를 받아와서 각 user, isLoading, isError 에 객체 형태로 담아준다(각 컴포넌트에서 활용)
  return {
    user: data,
    isLoading: !error && !data,  // !error && !data를 이용해 로딩 상태도 관리할 수 있다
    isError: error
  }
}


function Page () {
  return 
  <div>
    <Avatar />
    <Content />
  </div>
}


// child components
function Content () {
  const { user, isLoading } = useUser()
    if (isLoading) {
      return <Spinner />
    }
  return <h1>Welcome back, {user.name}</h1>
}

function Avatar () {
  const { user, isLoading } = useUser()
    if (isLoading) {
      return <Spinner />
    }
  return <img src={user.avatar} alt={user.name} />
}

🌈 http 요청을 통해 서버에서 데이터를 받아오는 방식으로는 Fetch API, Axios (Ajax API 통신용라이브러리) 등이 있다. 그러나 일단 작업이 완료되면 데이터를 캐시하거나 페이지를 매김하는 데 도움이 되지 않으므로 직접 처리해야 한다.

SWR은 캐싱, 페이지매김, 스크롤위치 복구, 종속 페치 등과 같은 기능들이 포함되어 있기 때문에 더욱 편리하다. 뿐만아니라 데이터가 항상 최신 상태인지 확인하기 위해 SWR은 네트워크가 복구 될 때 자동으로 재 검증해주기 때문에 자동 업데이트가 된다는 강력한 장점이 있다.

  • 데이터 fetch가 데이터가 필요한 컴포넌트에 바인딩되고, 모든 구성 요소가 서로 독립적이다.
  • 상위 컴포넌트는 데이터 혹은 전달에 대해 알 필요가 없어진다.
  • 동일한 SWR Key를 사용하면, 자동으로 중복 요청이 제거 되고, 요청이 캐시 되고 공유된다.
    즉, API 요청이 1 개만 전송 된다는 것이다.

🍀 fetch API

  • 서버에서 데이터를 가져오기 위한 인터페이스 제공 (XMLHttpRequest보다 더 강력)
    (XMLHttpRequest의 단점을 보완하기 위해 Fetch API를 도입하였다. 이는 HTTP요청에 최적화 되어 있고 Promise를 기반으로 되어있기 때문에 상태에 따른 로직을 추가하고 처리하는데에 최적화 되어 있다)
  • 요청하고 데이터(resource)를 가져오려면 fetch()메서드를 사용한다.
  • Fetch API는 3개의 Interface를 도입하고 있는데 Headers, Request, Response 이다. 이는 곧 HTTP의 개념과 대응되는 Interface이다.

💦 fetch API 의 특징

  • fetch()로 부터 반환되는 Promise 객체는 HTTP error 상태를 reject하지 않는다.
    (만약에, HTTP Statue Code가 404나 500을 반환하게된다면, ok 상태가 false인 resolve가 반환되게 된다. 그러나 네트워크 장애나 요청이 완료되지 못한 상태에는 reject가 반환된다.)
  • 보통 fetch는 쿠키를 보내거나 받지 않는다.
  • fetch() 함수는, 브라우저의 window 객체에 소속되어 있기 때문에 window.fetch()로 사용되기도 한다.

💦 fetch API 의 사용법

fetch(url, options)
  .then((response) => {response.json()})
  .then((data) => {console.log(data)})
  .catch((error) => {console.log("error:", error)})

첫번째 인자로 URL, 두번째 인자로 옵션 객체를 받게된다.
그래서, Promise 타입의 객체를 반환하게 되는데, 이 반환되어진 객체는, API 호출이 성공했을 경우에는 응답(response) 객체를 resolve하고, 실패했을 경우에는 예외(error) 객체를 reject하게된다.

옵션객체(options)는 HTTP 방식(method) / HTTP 요청헤더(headers) / HTTP 전문(body) 등을 설정이 가능하다.
그리고, 응답객체로 부터는 HTTP 응답상태(status), HTTP 응답헤더(headers), HTTP 응답전문(body) 등을 읽어올 수 있다.

❗️ fetch()메서드는 가져오려는 데이터(resource)의 경로인 하나의 필수 인수를 사용한다.

fetch('http://example.com/fetch')   // 하나의 필수 인수 = 데이터 경로
	.then((res) => { res.json() })  // json으로 변환
	.then((data) => { console.log('success :',data); })  // 성공적으로 받아왔을때
	.catch((error) => { console.log('error :', error); });  // 실패했을때

서버 응답이 HTTP오류 상태인 경우에도 서버가 헤더로 응답하는 즉시 해당 요청으로 Promise를 반환한다. (즉, 비동기로 성공적으로 데이터를 받아올 수 있으나, error인 경우에는 Promise객체를 반환하여 보여준다)
선택적으로 두 번째 인수로 options 객체를 전달할 수도 있다.

💦 fetch API 의 options에 request 적용

🌱 Request 설정 옵션
method : 사용할 메소드를 선택 (GET, POST, PUT, DELETE 등등)
headers : 헤더에 전달할 값
body : 바디에 전달할 값
mode : cors 등의 값을 설정 (cors, no-cors, same-origin)
cache : 캐쉬 사용 여부 (no-cache, reload, force-cache, only-if-cached)
credentials : 자격 증명을 위한 옵션 설정(include, same-origin, omit) (Default. same-origin)

fetch(url, {    // options에 설정 값들을 객체 형태로 넣어준다.
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  },
  'mode': 'cors'
})
  .then((response) => { response.json() }) 
  .then(data => { console.log('success :',data); })
  .catch((error) => { console.log(error) });

// 또는 아래와 같이 설정값들만 따로 모아 하나의 객체 변수에 저장할 수 있다
let optObj = {
  method: "GET",
  headers: {
  	'Content-Type': 'application/json'
  },
  'mode': 'cors'
};

fetch(url, optObj)
  .then((res) => { res.json() })
  .then(data => { return data })
  .catch(error => { console.log(error) })


// 데이터를 전송(POST)하는 경우에는 
// body에 JSON.stringify()로 변환하여 값을 추가한다
fetch(url, {
  method: 'POST',
  body: JSON.stringify({ sitename: 'webisfree' })
})
.then(function(response) {
  //...
});

❗️ Fetch API에서는 직접 JSON.stringify()를 사용하여 
JSON 타입의 문자열로 변환해야 한다.

🔨 캐시 vs 쿠키 차이점

profile
boma91@gmail.com

0개의 댓글