이제 직접 내가 만들던 linkbrary 프로젝트에 적용시켜 보겠다. 최근에 만들던 taskuit에 적용하면 더 좋겠지만 우선 내가 전부 작성한 코드에 실험을 해보는게 마음이 편하다...
우선 프로젝트 전반에 걸쳐 사용되는 데이터인 유저 정보를 리액트 쿼리를 적용시켜 보겠다. 왜냐하면 해당 정보를 사용해서 컴포넌트에서 사용하거나 api요청을 하기 때문이다.
useEffect(() => {
const userAccess = localStorage.getItem('token');
if (userAccess) {
const loadUser = async () => {
const response = await getUser(userAccess);
setUser(response[0]);
};
loadUser();
}
}, []);
기존의 코드이다. 로그인에 성공했을때 토큰을 로컬 스토리지에 저장하고 저장된 정보가 있을때 해당 토큰을 사용해서 유저 정보를 가져온다. 이제 이 부분에 리액트 쿼리를 적용시켜보겠다.
const { data: user } = useQuery({
queryKey: ['user'],
queryFn: () => getUser(),
staleTime: 60 * 1000 * 60,
});
쿼리키로 user로 지정하고 유저정보는 자주 갱신될 필요가 없기 때문에 한시간의 stale time을 지정해줬다. 이제 유저정보는 한시간에 한번만 새로 불러와진다.
약간의 문제가 생겼다. 애당초 유저 정보는 로그인 이후에 필요하기 때문에 로그인과 회원가입, 렌딩페이지에서는 요청을 보낼 필요가 없다.
<UserProvider>
<Nav />
<ModalProvider>
<Component {...pageProps} />
</ModalProvider>
</UserProvider>
하지만 유저 정보는 context로 관리하고 있고 provider가 모든 컴포넌트를 감싸고 있어서 특정 컴포넌트에서 제외하는것이 어렵다. 그래서 리액트 쿼리의 옵션을 추가해줘서 방지할 필요가 있었다.
리액트 쿼리에서는 외부 값에 의존해서 요청을 보내도록 옵션을 지정하는 것이 가능하다.
const [isLogin, setIsLogin] = useState(false);
일단 로그인 상태를 나타내는 state값을 하나 만들었다.
useEffect(() => {
if (localStorage.getItem('token')) {
setIsLogin(!isLogin);
}
}, []);
그리고 컴포넌트가 처음 실행될때 로컬스토리지에 있는 값을 확인해서 로그인 여부를 설정해준다.
const { data: user } = useQuery({
queryKey: ['user'],
queryFn: () => getUser(),
staleTime: 60 * 1000 * 60,
enabled: !!isLogin,
});
그리고 리액트 쿼리의 enabled 옵션을 줘서 isLogin이 true일때에만 api요청을 하도록 설계하는 것이다.

지금 로그인이 되지 않은 상태에서는 isLogin이 false이기 때문에 쿼리는 disabled상태이다. 그래서 api요청도 가지 않는다. 이제 로그인을 하게되면

isLogin이 true가 되면서 정상적으로 api요청이 가고 유저 정보가 잘 저장된다.
지금 코드를 리팩토링하면서 느낀점은 로컬 스토리지에 너무 의존하고 있다는 점이다... 지금 리팩토링을 진행하기전에 next-auth를 사용해서 그런가 로그인 상태를 확인하는 방법이 너무 원시적이라는 느낌이 든다. 빨리 리액트 쿼리를 적용하고 next-auth까지 적용을 해보고 싶다. 좀더 기대되는 것은 refreshToken까지 포함되어 있어서 조금더 다차원적인 인가 로직구현이 가능하지 않을까 싶다.
리액트 쿼리를 적용하고 있는데 재밌다. 비동기로 api요청하는 것이 은근 복잡하고 생각할게 많다고 생각했는데 모든걸 리액트 쿼리에서 해주고 눈으로 확인하기 쉬우니까 좋다. 앞으로 코드작성하는데 시간도 많이 단축될것 같다. 빨리 다른 부분도 적용시켜서 좋은 코드를 만들어보고 싶다.