token을 새로 받는 경우에
refreshToken이 만료되어 error가 발생 -> 특정 페이지로 redirect
axios interceptor를 사용중에 있고, error 발생 후 window.location.href="/"을 통해 redirect를 하면,
access token, refresh token 등을 redux store에서 지우는
로그아웃 처리와 header에서 Authorization을 지웠음에도 남아 있는 현상 발생
+ 페이지 전체 리로드시 리액트가 가지는 상태를 잃어버리는 단점
-> navigation을 활용해서 페이지 리다이렉트
navigation을 사용하는데 추가적인 문제상황
* 훅 문법으로 axios request 함수 내에서 사용이 제약적
- navigate를 변수 생성하여, 이 변수를 넘겨받아 처리
* navigate가 사용하려는 곳에서 준비되지 않아서 전달받지 못하는 문제 발생
- Promise (async, await) 사용으로 처리
예제 코드 커밋:
https://github.com/Junanjunan/g6_react/commit/afbe07ed5aed1685a289dad1819946cfa8a80f43
Flow
1. navigate 값을 얻을 수 있는 Promise를 활용
- Promise의 resolve를 통해서 얻는 값이 navigate (naviationFunction)이 될 수 있도록 처리
- new Promise((resolve) => {resolveNavigation = resolve});
-> resolveNavigation을 resolve의 refrerence로 만든다. (이 refrerence를 통해 외부에서 resolve 메소드를 커스텀)
- resolve의 reference인 resolveNavigation을 통해 resolveNavigation(navigate) 실행
-> navigationPromise는 navigate를 값으로 얻을 수 있음
- 즉 Promise의 resolve가 반환하는 값이 navigate가 되도록 함
// src/lib/useNavigationSetup.ts
import { useEffect } from 'react';
import { useNavigate, NavigateFunction } from 'react-router-dom';
let navigationPromise: Promise<NavigateFunction>;
let resolveNavigation: (navigate: NavigateFunction) => void;
navigationPromise = new Promise((resolve) => {
resolveNavigation = resolve;
});
export const setNavigation = (navigate: NavigateFunction) => {
resolveNavigation(navigate);
};
export const getNavigation = async (): Promise<NavigateFunction> => {
return navigationPromise;
};
export const useNavigationSetup = () => {
const navigate = useNavigate();
useEffect(() => {
setNavigation(navigate);
}, [navigate]);
};
2. 앱의 Root 단에서 navigate를 초기화
// src/components/Root.tsx
import { Box } from "@chakra-ui/react";
import { Outlet } from "react-router-dom";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import Header from "./Header";
import { useNavigationSetup } from "../lib/useNavigationSetup"; // **
// **
const NavigationSetup: React.FC = () => {
useNavigationSetup();
return null;
};
export default function Root() {
return (
<Box>
<NavigationSetup />
<Header />
<Outlet />
<ReactQueryDevtools />
</Box>
);
}
NavigationSetup을 컴포넌트화해서 아래와 같이 Root에 포함시킨다.
* NavigationSetup -> useNvigationSetup -> navigationPromise를 초기화 한다.
(1번의 로직이 Root 내의 NavigationSetup이 불러와지면서 실행)
3. navigate를 원하는 곳에서 전달받아서 사용 (Promise 이므로 async, await 활용)
// src/api.ts
import { getNavigation } from "./lib/useNavigationSetup"; // **
export const axiosInstance = axios.create({
baseURL: `${serverURL}/api/v1`
})
async function handleLogoutAndRedirect(): Promise<void> {
store.dispatch(tokenLogout());
store.dispatch(userLogout());
delete axiosInstance.defaults.headers.common["Authorization"];
alert("로그인이 필요합니다.");
const navigate = await getNavigation(); // **
navigate('/'); // **
}
navigationPromise를 얻을 수 있는 getNavigation 함수를 통해 navigate를 전달받아서 사용
'React' 카테고리의 다른 글
React: axios interceptor를 통해 request, response를 미들웨어 처리 (0) | 2024.06.29 |
---|---|
React: Component내의 element를 useRef를 통해 접근 및 값 변경 (0) | 2024.06.20 |
React: React 프로덕션 모드로 localhost 실행 시키기 # strict mode (0) | 2024.06.19 |
React: useForm을 활용해서 다른 컴포넌트 간에 변수 주고 받는 예제 # useForm # watch # useFormContext # 파일 업로드 (0) | 2024.06.18 |
React: Strict mode # useEffect # useRef (0) | 2024.06.13 |