useSWR을 사용하던 중 fetcher에 인자로 데이터를 보내야해서 공식문서를 참고하였다.
useSWR('/api/user', () => fetcher('/api/user'))
useSWR('/api/user', url => fetcher(url))
useSWR('/api/user', fetcher)
//fetcher
const fetcher = (url: string) => axios.get(url).then(result);
2번째 인자로 fetcher로 넣을때 위 3개의 expression은 같은 의미를 갖는다.
useSWR은 기본으로 첫번째 인자인 key를 fetcher 인자(url)로 넣어준다.
인자를 복수개로 넘기려면 어떻게 해야할까? API 요청시에 Auth Token을 넘겨야 하는 상황이다.
const token = '#123';
useSWR('/api/user', url => fetchWithToken(url, token))
//fetcher
const fetcherWithToken = (url: string, token: string) =>
axios
.get(url, {
headers: {
Authorization: `Bearer ${data.access_token}`,
},
})
.then(result => result.data);
이런식으로 넘기면 될듯 하다. 물론 정상적으로 fetcher 함수에 인자는 전달되고 요청은 정상적으로 진행된다.
하지만 컴포넌트에서 token값이 변경된다면? useSWR은 첫번째 인자인 '/api/user' = key값을 기준으로 데이터를 캐싱해둔다. token값이 변경되어도 이전의 token으로 요청한 데이터를 가지고 있을 것이고 이것은 사용자가 예상하는 값이 아니다. 해결 방법이 있을까?
const token = '#123';
useSWR(['/api/user', token], url => fetchWithToken(url, token))
token이 변경되면 다시 요청할 수 있는 방법은 key를 배열로 사용하면 된다. 이제 key값이 변경되면 해당 요청을 다시 진행한다. (useEffect의 deps와 유사하다..!)
위의 내용들을 이용하면 한 단계 넘어가서 useSWR 요청들끼리의 조건부 실행도 가능할 것 같다.
const { data: user } = useSWR(['/api/user', token], fetchWithToken)
const { data: orders } = useSWR(user ? ['/api/orders', user] : null, fetchWithUser)
아래의 '/api/orders'에 대한 요청은 '/api/users' 요청이 성공하여 user가 있을 경우에만 호출된다. user가 stable value인 경우에는 해당 로직은 정상적으로 진행이 된다.
하지만 user가 객체라면? useSWR은 useEffect와 마찬가지로 argument의 변화를 체크할 때 '얕은 비교(shallow compare)'를 사용한다.
const obj1 = { 1: 'red', 2: 'yellow' }
const obj2 = { 1: 'red', 2: 'yellow' };
console.log((obj1 === obj2) ? '지금은 맞다' : '그때는 틀리다');
//그때는 틀리다 출력!
그러므로 위의 /api/orders'에 대한 요청은 무한히 이루어지게 된다. (실제 테스트해보니 내 브라우저가 마치 디도스 공격을 하듯이 서버 요청을 연달아서 보냈다...😨)
const [name, setName] = useState('');
const [phone, setPhone] = useState(0);
const paramData = {
name,
phone
};
// 이렇게 요청을 보내면 매 렌더링 시에 paramData 부분은 같지 않다. (무한 요청)
useSWR(['/api/user', paramData], url => fetcher(url, paramData));
// stable 변수를 key로 사용하면 정상적으로 한번만 요청 진행
useSWR(['/api/user', name, phone], (url) => fetcher(url, paramData));
아래의 예와 같이 array 인자에 state들을 연결시켜주면 name이나 phone 상태가 변경되었을 시에 재요청이 가능하다..!