Duration
2022.11.21 ~ 2023.07.02
Skill Set
React18 / Typescript / GraphQL / React API / tailwind / vite3 / yarn berry / Recoil
Goal
랜더링 성능 최적화
개발 관리 포인트 최소화
시맨틱 태그를 고려한 화면 구현
Features
Auth 관련 기능 / 페이지네이션 기능 / 디자인 시스템 도입 / 리포트 공유하기 기능 / amplitude 셋팅 및 이벤트 설치 / 서비스 소개 페이지 퍼블리싱
회원가입, 로그인, 비밀번호 재설정, 아이디/비밀번호 찾기와 같은 기능 설계 및 화면 구현했습니다.
기존에는 화면이 랜더링 후 useEffect로 권한 체크가 되어서, 사용자에게 화면이 보인 다음에 로그인 페이지로 이동하던 이슈 / 화면 튐 현상
page가 랜더링되기 전, router단에서 회원여부를 확인하여 접근 제어 (react-router, recoil, grahpql 사용)
// ## 1. Router - 회원정보 조회 ## //
//회원정보 전역상태 (recoil)
const [userInfo, setUserInfo] = useRecoilState(UserAtom); //✅
//cookie에 저장된 회원토큰
const storageToken = authTokenStorage.getToken();
const clearUserInfo = signInApi().clearUserInfo;
const clearAmplitude = signInApi().clearAmplitude;
const navigation = useNavigate();
//회원 정보 셋팅
const { data: userQueryData } = useMeQuery(
{ token: storageToken },
{
// query는 선언과 동시에 작동되기에 enabled,refetchOnWindowFocus로 작동을 제어한다.
enabled: isFalsy(storageToken) === false, //✅
refetchOnWindowFocus: false, //✅
onSuccess: (res) => {
// 앰플리튜드에서 사용할 회원 정보 셋팅
if (isFalsy(useCookieStorage.getCookie('AMPLITUDE_USER_ID'))) {
_setUserId(res.me.id);
useCookieStorage.setCookie('AMPLITUDE_USER_ID', 'true', 1);
}
},
onError: (error) => {
// 전역 상태 초기화
clearUserInfo();
// 앰플리튜드 초기화
clearAmplitude();
navigation(PATH.SIGN_IN);
},
},
);
// ## 4. PrivateRoute - 페이지 이동 ## //
export default function PrivateRoute() {
const storageToken = authTokenStorage.getToken(); //✅
const saveReturnUrl = authReturnUrl().saveReturnUrl;
if (isFalsy(storageToken)) { //✅
{/* 접근을 시도한 url 상태에 저장 */}
saveReturnUrl(window.location.href); //✅
return <Navigate to={PATH.SIGN_IN} />;
} else {
return <Outlet />; //✅
}
}
// ## 2. Router - 회원정보 셋팅 ## //
//query가 실행되어 유저정보(userQueryData)가 변경된 경우, 전역상태 업데이트
useEffect(() => {
if (userQueryData && isFalsy(userInfo)) {
setUserInfo(userQueryData); //✅
}
}, [userQueryData]);
// ## 3. Router - 페이지 이동 ## //
return (
<Routes>
{routeList.map((route) => {
{/* 인증을 반드시 해야지만 접속 가능한 페이지 정의 */}
if (route.isPrivate) { //✅
return (
<Route key={route.path} element={<PrivateRoute />}> //✅
<Route //✅
key={route.path}
path={route.path}
element={createElement(route.component)}
/>
</Route>
);
}
return (
<Route
key={route.description}
path={route.path}
element={createElement(route.component)}
/>
);
})}
</Routes>
);
화면이 사용자에게 보이기 전 권한 체크가 진행되어 화면이 튀던 문제 개선됨
비회원이 회원만 접근할 수 있는 화면을 접근하려고 할 때, PrivateRouter로 인해 console.log가 출력된다.