guricode

[flutter-sns-project - 6] 트러블슈팅 - 로그인 수행시 Null오류 본문

앱/Flutter&Dart

[flutter-sns-project - 6] 트러블슈팅 - 로그인 수행시 Null오류

agentrakugaki 2025. 9. 2. 21:36

 

1. 문제 개요

  • 오류 상황: 로그인 버튼 클릭 시 인증 실패여도 홈으로 이동하거나, 비동기 처리 타이밍에 따라 엉뚱한 분기 발생.
  • 발생 배경: vm.login이 Future인데 await 없이 호출했고, 분기 조건을 if (UserState != null)로 작성했다.

2. 오류 코드 및 오류 메시지

  • 오류 코드: 명시적 예외 없음(논리 오류).
  • 오류 메시지: 화면 전환은 되지만 실패 케이스에서도 홈 진입. 드물게 비동기 타이밍 문제로 후속 코드에서 네비게이션 관련 경고 가능.
  • 관련 로그: print('test UserState is null')가 절대 호출되지 않음(조건이 항상 참이기 때문).

3. 원인 분석

  • 오류 원인 1: await 누락. vm.login 완료 전 분기 실행. Future<bool>의 결과를 사용하지 않음.
  • 오류 원인 2: 잘못된 조건식. UserState는 타입이므로 UserState != null은 항상 true.
  • 구조적 이해:
    • Flutter 비동기 모델에서 await 없이 UI 분기하면 상태 미반영 분기가 발생한다.
    • 네비게이션이나 setState 전에는 위젯 생존 여부(mounted) 확인이 안전하다.

4. 해결책

단계별 조치

  • Step 1: 로그인 호출에 await 추가해 완료를 보장.
  • Step 2: bool 결과로 분기하거나, 실제 프로바이더 상태를 읽어 분기.
  • Step 3: await 뒤 if (!mounted) return;로 생존 가드.

문제 코드

Future<void> _submit() async {
  if (_formKey.currentState!.validate()) {
    final email = _email.text.trim();
    final password = _password.text;

    vm.login(email, password); // await 누락
    if (UserState != null) {   // 타입 비교 → 항상 true
      context.pushNamed('home');
    } else {
      print('test UserState is null');
    }
  }
}

해결 코드

Future<void> _submit() async {
  if (_formKey.currentState!.validate()) {
    final email = _email.text.trim();
    final password = _password.text;

    final ok = await vm.login(email, password); // 결과 대기
    if (!mounted) return;                        // 생존 가드

    if (ok) {
      context.pushNamed('home');                 // 성공 시 이동
    } else {
      debugPrint('login failed or user state null');
    }
  }
}

5. 교훈 및 주의 사항

  • 비동기 결과에 의존하는 분기는 반드시 await 후 처리한다.
  • 타입 이름으로 null 체크하지 않는다. 인스턴스나 리턴값으로 판단한다.
  • 네비게이션·setState 전에는 mounted를 점검한다.
  • 실패 케이스 UX를 명확히 하자(스낵바·다이얼로그 등).