Recoil을 활용한 로그인 유지 기능

y___h·2023년 4월 12일
0

프로젝트에서 로그인 유지 기능을 구현하던 중 겪었던 어려움과 해결 과정에 대해 기록해보려 한다.

구현한 기능과, 권한 제한에 대한 내용은 다음과 같다.

기능

- 최초 로그인 시, 받은 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

최종 로직 흐름은 다음과 같다.

  • 최상단 컴포넌트에서 API를 호출하여 token 유효 여부 확인
// Header
...
  const { me } = useMe();
...
  useEffect(() => {
    if (me) {
      setIsLogin(true);
    } else {
      setIsLogin(false);
    }
  }, [me]);
  • 유효하다면, login atom의 상태를 update하고 이를 구독하고 있는 컴포넌트들도 update 된다.
  • 유효하지 않다면, login atom의 default (=logout) 값이 유지 되고, 변화가 일어나지 않는다.
  • 어느 페이지에서 새로고침을 하던, 최상단 컴포넌트는 항상 존재하기 때문에 이 로직은 웹 어플리케이션에 최초 접근 시 항상 실행된다.

구현 결과
login atom을 구독하고 있는 컴포넌트 들 중 하나이다. atom의 상태에 따라 잘 작동하는 모습이다.

profile
기록 이사중 🐣

0개의 댓글