S
(stail) W
(while) R
(revalidate) = 처음 캐시로부터 데이터를 가져오고(stale), fetch요청을 보내 revalidating하여 최신 데이터를 유지한다.Data Fetching 라이브러리
) 💦 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
fetcher
(1) useSWR 의 첫번째 인자인 key
값을 기준으로 중복 요청을 제거하고, 캐시를 하며, 해당 값을 마치 전역 상태관리처럼 share 까지 해준다.
(2) useSWR 의 두번째 인자인 fetcher
은 SWR 내부적으로 구현되어있는 것이 아니라 사용자가 직접 정의하는 것이다. 때문에 fetch, axios 던 문제 없이 사용 가능하다.
data
error
일반적으로 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()
메서드를 사용한다. Headers
, Request
, Response
이다. 이는 곧 HTTP의 개념과 대응되는 Interface이다.💦 fetch API 의 특징
💦 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 타입의 문자열로 변환해야 한다.