문제상황
로그인안한 상태에서 특정페이지에 갈때마다 redirect를 해야하는데, 어딜가도 리다이렉트가 발생한다.
관련 로직을 내가 짰진 않았지만 해결해보려고 한다.
현재상황
[//전략,
{
id: 4,
label: '리뷰 작성 페이지',
path: '/reviews/writer',
element: <ReviewWriter />,
isLayout: true,
withAuth: true,
},//후략,
]
저런 객체들을 createBrowserRouter에 넘겨줘서 페이지를 구성했다.
withAuth가 로그인돼야 접속할 수 있는 사이트였는데, 현재는 저것이 따로 쓰이지 않았다(withAuth로 처리해주는게 없었다).
따라서 withAuth는 문제가 없었다.
리다이렉션이 일어나는 곳의 공통점은 isLayout=true였고 isLayout을 true로 설정시 페이지에 헤더같은 공통 컴포넌트가 포함된다.
헤더의 코드엔 useAuthRedirect란 커스텀훅을 사용하고 있었다.
const useAuthRedirect = () => {
const [isLoggined, setIsLoggined] = useRecoilState(UserProfileAtom)
const {isLoading} = useQuery({
queryFn: fetchUserProfile,
queryKey: ['userProfile'],
options: {
onSuccess: data => {
setIsLoggined(data)
},
onError: error => {
console.log(error, '토큰이없습니다')
window.location.href('/sign-in') // 리다이렉션발생!
},
staleTime: Infinity,
retry: 0,
},
})
return {isLoggined, isLoading}
}
export default useAuthRedirect
당연히 로그인 안한 상태에서 자신의 프로필정보를 받아오려하면 에러가 날 것이고 onError로 인해 리다이렉트가 발생할 것이다.
그래서 커스텀훅에서 해당부분을 지웠지만 리다이렉트는 계속됐다.
그럼 저것이 근본적인 문제는 아니였던 것이다.
하지만 헤더에서 사용한 useAuthRedirect 커스텀훅을 지운다면 리다이렉트가 발생하지 않았다.
그래서 용의자를 queryfn으로 좁혀봤다.
export const fetchUserProfile =
async (): Promise<IfLoginUserProfileResponse> => {
const {data} = await instance.get('/me')
return data
}
단순히 get만 해온다. 특정한 오류처리는 하지 않는다.
하지만 저 api가 문제이므로 instance를 들어가보자.
export const httpErrorHandler = async (
error: AxiosError<ErrorResponse> | Error,
): Promise<Error> => {
// 401에러인 경우 로그인 페이지로 이동
if (isServerError(error) && error.response?.status === 401) {
try {
// 토큰 갱신 API 요청
const response = await fetchRefreshToken()
if (response?.status === 200) {
window.location.reload()
}
} catch (refreshError) {
// 토큰 갱신에 실패한 경우 로그인 페이지로 이동
// 원인
window.location.href = '/sign-in'
//
console.log(refreshError, '리프레시 에러')
}
}
return Promise.reject(error)
}
instance.interceptors.response.use(
(response: AxiosResponse) => response,
async (error: AxiosError<ErrorResponse> | Error) =>
await httpErrorHandler(error),
)
사용하고 있던 instance에서 401에러인 경우 리프레쉬하고 거기서도 에러가 난다면 로그인 페이지로 리다이렉트 시킨다.
로그인 안된상태라면 당연히 리다이렉트가 될 것이다.
따라서 저것을 지워준다.
더 나아가서
문제되는 것들을 다 지웠더니 리다이렉트가 아무곳에서 발생하지 않는다.
이제 정말로 로그인이 필요한 페이지와 아닌페이지를 분류하고, 로그인 필요한 페이지에 진입하려고 할때만
라우터의 withAuth를 이용해 리다이렉트 시켜보자.
interface proptype{
children:ReactNode
}
const AuthRedirect = ({children}:proptype) => {
const data = useAuthRedirect()
if (data.isLoading){
return <></>
}
if (data.isLoggined === null) {
window.location.href = "/sign-in"
return <></>
}
return <>{children}</>
}
export default AuthRedirect
useAuthRedirect는 이제 promise<유저프로필>을 리턴한다.
로딩이 완료시 오류가 있다면 null이고 아니라면 유저프로필이 들어온다.
따라서 해당 조건을 처리해준다.
export const router: RemixRouter = createBrowserRouter(
routerData.map(router => {
let element: ReactNode = router.element
// 공통 레이아웃 추가
if (router.isLayout) {
element = <GeneralLayout>{element}</GeneralLayout>
}
// 로그인 안되면 리다이렉션
if (router.withAuth) {
element = <AuthRedirect>{element}</AuthRedirect>
}
// 따라서 로그인이 안됐는데 권한 필요한 페이지들어가면 빈화면이 보인 뒤 리다이렉션이 됨
return {
path: router.path,
element: element,
}
}),
)
'개발' 카테고리의 다른 글
github oauth2 클라이언트와 서버 구현해보기 -1 (0) | 2024.02.12 |
---|---|
react-hook-form을 이용한 복잡한 폼 구현 feat checkbox (1) | 2024.01.11 |
react-hook-form 폼 유효성 검사기능을 추가한 뒤 submit이 안될 때 (0) | 2024.01.07 |
반복되는 컴포넌트 key에 index를 넣으면 안되는 이유 (0) | 2024.01.03 |
react-hook-form 을 사용해봤다. (0) | 2024.01.01 |