프로젝트에서 로그인 유지 기능을 구현하던 중 겪었던 어려움과 해결 과정에 대해 기록해보려 한다.
구현한 기능과, 권한 제한에 대한 내용은 다음과 같다.
기능
- 최초 로그인 시, 받은 token을 localStorage에 저장
- 이후 웹 사이트에 최초 접속 시 localStorage의 token을 확인하여 로그인 상태를 유지
로그인 상태에 따라 기능 제한에 대한 기획
첫번째 시도
- 로그인 상태가 필요한 모든 컴포넌트에서 매번 API 호출
- localStorage에 저장된 token을 활용하여 유저 정보(내 정보)를 받아오는 API 호출 → 성공 시, 로그인 상태 유지 (useState)
1️⃣ 위 사진과 같이, **로그인 상태의 UI(프로필)와 비로그인 상태의 UI가 공존**하는 상황이 자꾸 생김.
2️⃣ 네트워크 비용을 고려하지 않았음.
3️⃣ 페이지 새로고침 시, 로그인 상태가 풀림 (state 초기화)
원인 : 하나의 통일된 상태가 아닌, 각각 API 호출하여 로그인 상태를 유지했기 때문. 이 땐, 토큰의 유효 여부를 매번 확인해야한다고 생각했던 것 같음.
해결 방법 도출
1️⃣ 위 사진과 같이, 로그인 상태의 UI(프로필)와 비로그인 상태의 UI가 공존하는 상황이 자꾸 생김.
2️⃣ 네트워크 비용을 고려하지 않았음.
→ Recoil 활용하여 로그인 상태 전역으로 관리하고,
로그인 상태가 필요한 컴포넌트에서 해당 상태를 구독하는 방식으로 변경
3️⃣ 페이지 새로고침 시, 로그인 상태가 풀림 (state 초기화)
→ 각 페이지 접근 시 useEffect를 활용하여 token 유효 여부 확인하여
login atom 상태 업데이트
여러 전역관리 툴이 있지만, Recoil을 선택한 이유는 다음과 같다.
전역 상태관리가 필요한 데이터가 적음(로그인 상태, 모달 관련 state) → Recoil, Context API 중 선택
로그아웃 상태 → 로그인 상태
로 변하며 변경되는 컨텐츠가 많지 않고 한 페이지당 그려야 하는 UI가 많은 편이라, 하위 컴포넌트를 모두 리랜더링하는 ContextAPI의 단점은 속도 저하가 우려됨.
→ 따라서 Recoil이 적합
두번째 시도
첫번째 시도에서 도출한 해결 방법 적용
- 로그인 상태가 필요한 모든 페이지에서 저장된 토큰을 활용해 내 정보를 받아오는 API 호출하고, 성공 시 전역 상태 update
- 모든 페이지에서 새로고침(refresh) 대응을 하기 위함
문제 : 이전에 컴포넌트 단위로 호출하던 것 보단 괜찮지만, 여전히 네트워크 비용 낭비. 동일한 로직 반복으로 비효율적.
고민 : 한 번만 요청할 순 없을까?
해결 방법 도출 : 항상 존재하는 컴포넌트에서 한 번만 요청하자!
세번째 시도
두번째 시도에서 도출한 해결 방법 적용
- 최상단 컴포넌트에서 API 호출 1회, 전역상태 update
최종 로직 흐름은 다음과 같다.
// Header
...
const { me } = useMe();
...
useEffect(() => {
if (me) {
setIsLogin(true);
} else {
setIsLogin(false);
}
}, [me]);
구현 결과
login atom을 구독하고 있는 컴포넌트 들 중 하나이다. atom의 상태에 따라 잘 작동하는 모습이다.