개발자
아래 코드처럼 리액트쿼리로 사용자 인증 코드를 구현했습니다. ( 외국 개발자분 코드 분석해서 거의 복붙하고 조금 수정 ) 간단히, api요청을 해서 유저 정보를 받아 로컬스토리지에 저장해서 사용하는 코드입니다. 이 훅을 프라이빗 라우터 및 로그인 버튼 or 사용자 이름 표시 UI 에 사용중인데요 쿼리 캐시 때문에 계속 요청을안하고 그값만 계속 사용중인데 이 사용자의 토큰 유효기간이 지났는데도 계속 그 값만 사용중입니다. 이 분기처리를 어떻게 해줘야할지를 모르겠습니다. 처음엔 refetchOnMount: false,를 true로 바꿔주고 토큰 유효값이 지나면 에러를 뱉어주는거를 보고 흡족해했으나 네트워크탭을 살펴보니 새로고침, 페이지 인아웃 할때마다 계속 요청을하고있어서 다시 고민에빠졌습니다. 어떤식으로 해줘야 할까요?.. 가장 생각나는건 statleTime 값을 토큰 유효기간 값만큼 설정해주면 될까 인데.. 이렇게해줘도되나요?
1import { useQuery, useQueryClient } from '@tanstack/react-query';
2import instance from 'api/instance';
3import { IUserInfo } from 'interface/auth';
4import { useEffect } from 'react';
5import { userKey } from 'react-query-key/auth.keys';
6import * as userLocalStorage from './user.localstorage';
7
8const fetchUserInfo = async (user: any) => {
9 const token = localStorage.getItem(userLocalStorage.USER_LOCAL_STORAGE_KEY);
10 const res: any = await instance.get('/api/auth', {
11 headers: {
12 Authorization: `Bearer ${JSON.parse(token as any).token}`,
13 },
14 });
15
16 return res.data;
17};
18
19interface IUseUser {
20 user: IUserInfo | null;
21}
22
23export function useUser(): IUseUser {
24 const queryClient = useQueryClient();
25
26 const { error, data: user } = useQuery({
27 queryKey: [userKey.user],
28 queryFn: async () => await fetchUserInfo(userLocalStorage.getUser()),
29 initialData: userLocalStorage.getUser,
30 refetchOnMount: false,
31 refetchOnWindowFocus: false,
32 refetchOnReconnect: false,
33 });
34
35 useEffect(() => {
36 if (!user || error) {
37 queryClient.setQueryData([userKey.user], null);
38 userLocalStorage.removeUser();
39 } else userLocalStorage.saveUser(user);
40 }, [user, error, queryClient]);
41
42 return {
43 user: user ?? null,
44 };
45}
답변 2
개발새발
작성자
없다고 비전공 • 2024년 04월 01일
저도 첨에 그렇게 생각했는데.. 주로 PrivateRoute에서 저 코드를 훅으로 사용합니다. 근데 이렇게되면 토큰이 만료된 상태인데도 여전히 사용자는 정상작동하는것처럼 보였습니다. 401에러를 뱉어야되는데 그러지도 않고.. 그래서 그냥 옵션으로 토큰 유효기간 만큼의 시간을 주는식으로했습니다. staleTime: 1000 * 60 * 10, // 10분 refetchInterval: 1000 * 60 * 10, // 10분 리프레쉬인터벌이 작동하면 토큰도 유효기간이 끝나니까 401을뱉고, 리프레시 토큰 api가 작동해서 자동으로 토큰유효기간을 연장해주는 식으로했습니다.. 이게 맞는건진 모르겠는데 일단 이렇게했습니다..ㅜ
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
커리어리 AI 봇
GPT가 달아주는 답변입니다.
2024년 03월 31일
리액트 쿼리의 `staleTime` 설정을 토큰의 유효 시간과 같게 설정하는 것은 올바른 해결책일 수 있습니다. 이렇게 하면 토큰이 만료되는 동시에 데이터가 "stale" 상태가 되고, 다음 개인 정보 요청에서 자동으로 새로운 데이터를 가져옵니다. ```javascript export function useUser(): IUseUser { const queryClient = useQueryClient(); const tokenExpiry = userLocalStorage.getUser()?.tokenExpiry; ... const { error, data: user } = useQuery({ queryKey: [userKey.user], queryFn: async () => await fetchUserInfo(userLocalStorage.getUser()), initialData: userLocalStorage.getUser, refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false, staleTime: tokenExpiry // Add this line }); ... } ``` 그러나 이 방법은 토큰 만료 시간을 정확하게 알고 있어야 합니다. 또한 서버에서 토큰이 만료되었다는 응답을 받으면 로컬 스토리지에서 토큰을 제거하고 사용자를 로그아웃 처리해야합니다. 또는 아니면 any로 선언된 res 부분에 타입을 지정해서 response가 오류일 경우 에러 핸들링하는 로직도 필요할 것 같습니다. 이 경우에는 사용자의 토큰이 만료되면 서버에서 401 Unauthorized 응답을 전송할 것입니다(만약 그렇게 구성되어 있다면). 이 에러를 캐치하면 로그인 페이지로 리디렉션나 다른 오류 처리를 할 수 있습니다. ```javascript const fetchUserInfo = async (user: any) => { const token = localStorage.getItem(userLocalStorage.USER_LOCAL_STORAGE_KEY); try { const res: ResponseTypeHere = await instance.get('/api/auth', { // replace 'ResponseTypeHere' with actual type. headers: { Authorization: `Bearer ${JSON.parse(token as any).token}`, }, }); return res.data; } catch (err) { if (err.response.status === 401) { // the token has expired or is invalid. Handle this error here. userLocalStorage.removeUser(); } } }; ``` 추가적으로, 항상 최신 상태를 유지해야하는 데이터의 경우 staleTime을 지정하지 않거나 짧은 시간을 설정하는 것이 좋습니다. 한편, 자주 바뀌지 않는 데이터의 경우 staleTime 값을 길게 설정해 네트워크 요청을 줄일 수 있습니다. 따라서 토큰 유효값에 맞춰서 staleTime을 설정하는 것은 올바른 접근 방식일 수 있습니다.
지금 가입하면 모든 질문의 답변을 볼 수 있어요!