Expo Router v2 전환 과정에서 발생한 라우팅 및 인증 상태 관리 문제

oversleep·2025년 3월 22일
0

troubleshooting

목록 보기
17/19

발단

기존에 React Navigation과 app.tsx를 사용하던 전통적인 방식에서 Expo Router v2로 전환하는 과정에서 문제가 발생했습니다.
Expo Router는 파일 시스템 기반 라우팅을 사용하기 때문에, 기존의 컴포넌트 기반 네비게이션과는 구조와 동작 방식이 크게 달랐습니다.

주요 문제점

  1. 인증 상태와 라우팅 연동: 로그인/로그아웃 상태에 따라 적절한 화면으로 이동해야 했지만, 여러 컴포넌트에서 라우팅을 시도하면서 무한 루프가 발생했습니다.

  2. AsyncStorage와 React 상태 불일치: AsyncStorage에서 토큰을 저장하거나 제거해도 React의 상태(isLoggedIn)가 자동으로 업데이트되지 않아 화면 전환 로직이 올바르게 작동하지 않았습니다.

  3. Not Found 화면 처리: 유효하지 않은 경로로 접근할 때 +not-found.tsx 화면으로 이동했다가 다시 리디렉션을 시도하면서 무한 루프가 발생했습니다.

  4. 비동기 작업의 타이밍 문제: 토큰 저장/제거와 화면 전환 사이에 타이밍 이슈가 있어 상태가 완전히 반영되기 전에 라우팅이 시도되었습니다.

해결 방법

1. 인증 상태 관리 통합

_layout.tsx에서 하나의 중앙 집중적인 인증 상태 관리를 구현했습니다:

export const AuthContext = createContext<AuthContextType | null>(null);

export default function RootLayout() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  // ...

  return (
    <AuthContext.Provider value={{ isLoggedIn, setIsLoggedIn }}>
      <LogoutHandler />
      <Slot />
    </AuthContext.Provider>
  );
}

2. 라우팅 로직 개선

무한 루프를 방지하기 위해 라우팅 상태를 추적하는 ref를 사용했습니다:

const hasNavigated = useRef(false);

useEffect(() => {
  if (isLoading || hasNavigated.current) return;
  
  // 라우팅 로직
  if (isNotFound || segments.length === 0) {
    hasNavigated.current = true;
    
    if (isLoggedIn) {
      router.replace("/(tabs)");
    } else {
      router.replace("/(auth)/start");
    }
  }
  // ...
}, [isLoading, isLoggedIn, segments]);

// 세그먼트가 변경될 때 라우팅 상태 초기화
useEffect(() => {
  hasNavigated.current = false;
}, [segments]);

3. 로그아웃 기능 개선

로그아웃 시 비동기 작업과 상태 업데이트를 올바르게 처리하도록 수정했습니다:

const handleLogout = async () => {
  try {
    // AsyncStorage 데이터 제거
    await AsyncStorage.multiRemove([
      "isLoggedIn",
      "accessToken",
      // ...
    ]);

    // React 상태 업데이트
    if (setIsLoggedIn) {
      setIsLoggedIn(false);
    }

    // 약간의 지연 후 라우팅
    setTimeout(() => {
      router.replace("/(auth)/start");
    }, 100);
  } catch (error) {
    console.error("로그아웃 실패:", error);
  }
};

지연을 주는 이유는 상태 업데이트와 AsyncStorage 작업이 완료된 후 라우팅이 실행되도록 하기 위함입니다. 이렇게 하면 경쟁 상태(Race Condition)를 방지하고 일관된 상태에서 화면을 전환할 수 있습니다.

4. 파일 시스템 기반 라우팅 적응

Expo Router는 각 라우트 파일에 기본 내보내기(default export)가 필요합니다:

export const MatchingScreen = () => { // 잘못된 내보내기
  // 컴포넌트 코드
};

const MathcingScreen = () => {
  // 컴포넌트 코드
}
export default MatchingScreen; // 기본 내보내기 추가

결론

Expo Router v2로 전환하면서 파일 시스템 기반 라우팅인증 상태 관리를 올바르게 통합하는 방법을 배웠습니다.
특히 비동기 작업과 상태 업데이트의 타이밍 문제를 해결하는 것이 중요했습니다.

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

0개의 댓글