- Published on
SWR (state-while-revalidate)
- Authors
- Name
- Inhwan Cho
SWR
reactQuery와 유사합니다 reactQuery는 기능이 더 많지만 용량도 크기 때문에, 간단한 용도로 사용할때는 SWR이 적합합니다.
page에 접근 -> SWR(fetch data -> 캐싱) -> 다른 페이지(혹은 다른 화면) -> page 접근 -> SWR(API 호출 - 데이터가 바뀐게 있는지 확인 - loading이 없고 캐시에 있는 데이터 먼저 사용) -> 바뀐게 없으면 기존의 data(캐시에 있는) 사용 -> 바뀐게 있으면 data update
즉, 기존의 fetch를 사용하면 page에 접근 했을때 마다
undefined와 data를 받는데, SWR를 사용하면 data변경이 없으면 처음 page에 접근 할 때만
data를 받게됩니다.
그렇기 때문에 reactQuery
나 SWR
같은 캐싱을 이용한 방법을 사용해야합니다.
기존의 fetch 방법과 비교
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
export default function Home() {
const [user, setUser] = useState();
const router = useRouter();
useEffect(() => {
fetch("/api/users/home")
.then((response) => response.json())
.then((data) => {
if (!data.ok) {
return router.replace("/login");
} else {
setUser(data.profile);
}
})
.catch((error) => {
console.log(error);
});
}, [router]);
return user;
}
- 단 fetch로 불러온 데이터는 캐싱이 되지 않음.
SWR 사용하기
- 방법 1. 상위 layout에 SWRConfig를 감싸기(추천)
<SWRConfig value={{
fetcher: (url: string) =>
fetch(url).then((response) => response.json()),
refreshInterval:2000,
}}>
<Component/>
</SWRConfig>
import useSWR from "swr";
export default function useUser() {
const { data, error } = useSWR('/api/users/home')
// ...
}
- 방법 2. SWRConfig를 사용하지 않고 하나씩 fetcher를 생성(비추천)
import useSWR from "swr";
const fetcher = (url: string)=> fetch(url).then((response)=>response.json())
export default function useUser() {
const { data, error } = useSWR('/api/users/home', fetcher)
const router = useRouter();
useEffect(()=>{
if(data && !data.ok){
router.replace('/login')
}
},[data, router])
return { user: data?.profile, isLoading: !data && !error };
}
useSWR(key, fetcher)에 인자가 2개가 들어가는데, key에 url이 들어가는데 이 url이 캐싱이 될 때의 key(super_cache)값으로 들어갑니다.
참고로 router.push()는 페이지를 이동(전페이지에 대한 뒤로가기 기록이 있음) 그래서 뒤로가기를 누르면 전페이지 이동-> push()한 페이지로 이동됨 router.replace()는 페이지를 이동시키고 기록을 남기지 않음 즉 (뒤로가기를 누르면 그 전페이지가 아닌 전전페이지로 이동하게 만듦)
mutate
먼저 useSWR로 data와 mutate를 받는데, 이 mutate는 data와 동일한 형태이며, mutate를 변경 시 data를 변경합니다. 이를 이용하여 백엔드로 데이터를 넘기고 받아오기 전에 UI를 front에서 미리 바꿀 수 있게 많이 사용합니다. 특히, 현재 보고 있는 페이지 내의 데이터를 변경하는것을 unbound mutate
, 현재 보고있는 페이지 외의 데이터를 변경하는 것을 bound mutate
라 합니다.
- unbound mutate
import useSWR from "swr";
export default function likeTest() {
const apiAddress = 'https://sadfsfadsf.com'
const { data, mutate } = useSWR(apiAddress);
// mutate를 이용하여 전체 기존의 데이터를 넣고, 바꾸고 싶은 데이터를 첫번째 인즈에 넣고,
// 두번째 인자에는 true는 재검증(refetch)하여 백엔드의 데이터와 일치하는지 확인.(default)
// false는 재검증을 하지 않아 바뀐 값 그대로 front 에서만 유지합니다.
const handleLike = () => {
if (!data) return; //여러번 클릭 시 1회만 실행
mutate({
...data,
isLiked: !data.isLiked
}, false);
};
// mutate로 apiAddress를 다시 할 경우 재검증을 하게됩니다.
const handleRefetch = () => {
if (!data) return; //여러번 클릭 시 1회만 실행
mutate(apiAddress)
}
return (
<div className="grid grid-cols-2 gap-5 mx-6 my-2">
<div onClick={handleRefetch} className={`bg-white p-4 rounded-lg flex justify-center cursor-pointer`}>Let's refetch!</div>
<div onClick={handleLike} className={`${data.isLiked ? 'bg-red-300' : 'bg-blue-400'} p-4 rounded-lg flex justify-center cursor-pointer`}>{data.isLiked ? 'Unlike' : 'Like'}</div>
</div>
)
}
- bound mutate
주로 로그아웃 같은 전역 변수를 수정할때 사용합니다.
import { useSWRConfig } from "swr"
function App() {
const { mutate } = useSWRConfig()
mutate(key, data, options)
}