React Native 인증 상태 영구 저장 완벽 가이드

oversleep·2025년 2월 16일
0

app-development

목록 보기
11/38
post-thumbnail

1. 소개

React Native 앱에서 로그인 상태를 유지하는 것은 매우 중요한 기능입니다.
사용자가 앱을 종료했다가 다시 실행하거나, 새로고침을 했을 때도 로그인 상태가 유지되어야 좋은 사용자 경험을 제공할 수 있습니다.

2. 일반적인 실수와 문제점

2.1 조건부 렌더링의 함정

// ❌ 잘못된 방식(처음 시도)
<Stack.Navigator>
  {isLoggedIn ? (
    <Stack.Screen name="MainTab" component={MainTabNavigator} />
  ) : (
    <>
      <Stack.Screen name="Start" component={StartScreen} />
      <Stack.Screen name="Login" component={LoginScreen} />
    </>
  )}
</Stack.Navigator>

이 방식의 문제점:

  • 새로고침 시 상태 초기화
  • 화면 전환 시 깜빡임 발생
  • 네비게이션 스택 관리의 어려움

3. 올바른 구현 방법

3.1 기본 설정

import AsyncStorage from "@react-native-async-storage/async-storage";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";

const Stack = createStackNavigator<RootStackParamList>();

3.2 상태 관리와 초기화

export default function App() {
  const [isLoading, setIsLoading] = useState(true);
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(() => {
    const checkLoginStatus = async () => {
      try {
        // 로그인 상태와 토큰 모두 확인
        const [loginStatus, token] = await AsyncStorage.multiGet([
          "isLoggedIn",
          "accessToken",
        ]);
        // multiGet의 반환값 형태:
        //	[
        //  	["isLoggedIn", "true"],  // loginStatus = ["isLoggedIn", "true"]
        //  	["accessToken", "eyJhbG..."] // token = ["accessToken", "eyJhbG..."]
        //	]
        if (loginStatus[1] === "true" && token[1]) {
          setIsLoggedIn(true);
        } else {
          // 불완전한 상태일 경우 클리어
          await AsyncStorage.multiRemove(["isLoggedIn", "accessToken"]);
          setIsLoggedIn(false);
        }
      } catch (error) {
        console.error("Error checking login status:", error);
        setIsLoggedIn(false);
      } finally {
        setIsLoading(false);
      }
    };

    checkLoginStatus();
  }, []);
}

3.3 올바른 네비게이션 구조

// ✅ 권장되는 방식
return (
  <NavigationContainer>
    <Stack.Navigator 
      screenOptions={{ headerShown: false }}
      initialRouteName={isLoggedIn ? "MainTab" : "Start"}
    >
      <Stack.Screen name="Start" component={StartScreen} />
      <Stack.Screen name="Login" component={LoginScreen} />
      <Stack.Screen name="Signup" component={SignupScreen} />
      <Stack.Screen name="MainTab" component={MainTabNavigator} />
    </Stack.Navigator>
  </NavigationContainer>
);

4. 주요 개선사항 설명

4.1 조건부 렌더링 제거

  • 모든 스크린을 항상 네비게이터에 등록
  • initialRouteName을 통한 초기 화면 설정
  • 네비게이션 스택의 안정성 확보

4.2 토큰 검증 강화

  • isLoggedIn 상태와 토큰 동시 검증
  • 불완전한 상태 자동 정리
  • 안전한 로그인 상태 보장

4.3 로딩 상태 관리

if (isLoading) {
  return null;  // 또는 로딩 스피너 표시
}

5. 구현 시 주의사항

5.1 보안

  • 민감한 정보는 암호화하여 저장
  • 토큰 만료 시간 확인 로직 추가
  • 자동 로그아웃 메커니즘 구현

5.2 성능

  • AsyncStorage 호출 최소화
  • 불필요한 상태 업데이트 방지
  • 효율적인 에러 핸들링

5.3 사용자 경험

  • 로딩 상태 표시
  • 부드러운 화면 전환
  • 오류 발생 시 적절한 피드백

6. 베스트 프랙티스

  1. 토큰 관리

    const [loginStatus, token] = await AsyncStorage.multiGet([
      "isLoggedIn",
      "accessToken",
    ]);
    • 여러 키를 한 번에 조회하여 성능 최적화
    • 토큰 존재 여부 확인으로 안정성 강화
  2. 에러 처리

    try {
      // 로그인 상태 확인
    } catch (error) {
      console.error("Error checking login status:", error);
      setIsLoggedIn(false);  // 안전한 기본값 설정
    }
    • 모든 예외 상황 처리
    • 사용자에게 적절한 피드백 제공
  3. 상태 초기화

    await AsyncStorage.multiRemove([ // 사용자가 로그아웃 시
      "isLoggedIn",
      "accessToken",
      "refreshToken",
    ]);
    • 사용자가 명시적으로 로그아웃 시 상태 초기화
    • 인증 관련된 모든 상태 동시 제거
    • 일관성 있는 상태 관리

7. 결론

React Native에서 인증 상태를 영구적으로 저장하고 관리하는 것은 복잡할 수 있지만, 올바른 접근 방식을 따르면 안정적이고 사용자 친화적인 구현이 가능합니다.

핵심 포인트를 정리하면:

  1. 조건부 렌더링 대신 initialRouteName 사용
  2. 토큰과 로그인 상태 동시 검증
  3. 안전한 상태 초기화와 에러 처리
  4. 효율적인 AsyncStorage 사용

이러한 가이드라인을 따르면 새로고침에도 견고하게 동작하는 인증 시스템을 구축할 수 있습니다.

profile
궁금한 것, 했던 것, 시행착오 그리고 기억하고 싶은 것들을 기록합니다.

0개의 댓글