guricode

트러블슈팅: “프로필 이미지 선택만 했는데 바로 서버에 업로드됨” 본문

앱/Flutter&Dart

트러블슈팅: “프로필 이미지 선택만 했는데 바로 서버에 업로드됨”

agentrakugaki 2025. 8. 12. 18:11

증상

 

  • 갤러리에서 이미지를 선택만 했는데, 바로 Firebase Storage에 업로드되고 Firestore에도 URL이 저장됨.
  • 의도는 ‘시작하기’ 버튼을 눌렀을 때만 업로드/저장.

 

 

원인

 

  • 이미지 선택 핸들러(_pickAndUpload)에서 업로드 메서드를 바로 호출함.
  • 그래서 다른 요소(이름,지역설정)을 설정 안했는데도 파이어스토어에 이미지가 업로드돼어버림
// 문제 코드
final picked = await picker.pickImage(...);
if (picked == null) return;
await ref.read(userViewModelProvider.notifier)
         .uploadAndSaveProfileImage(File(picked.path)); // ← 즉시 업로드

 

 

 

해결 전략

 

  1. 선택 시점에는 업로드 금지, 로컬 경로만 상태에 보관(미리보기 용).
  2. ‘시작하기’ 버튼에서만 업로드 + Firestore 저장 실행.

 

 

수정 코드

 

 

1) 선택 시: 로컬 경로만 저장

Future<void> _pickImage() async {
  final picker = ImagePicker();
  final picked = await picker.pickImage(source: ImageSource.gallery);
  if (picked == null) return;

  // 업로드 금지, 로컬 경로만 저장해서 미리보기
  ref.read(userViewModelProvider.notifier).setLocalImagePath(picked.path);
  setState(() {}); // 미리보기 갱신
}

 

2) 미리보기: 로컬이 우선

final localPath = ref.read(userViewModelProvider.notifier).localImagePath;

child: (localPath != null && localPath.isNotEmpty)
  ? Image.file(File(localPath), fit: BoxFit.cover)
  : const Icon(Icons.add, size: 25, color: Colors.white),

 

3) ‘시작하기’에서만 업로드 + 저장

onTap: canStart ? () async {
  try {
    await ref.read(userViewModelProvider.notifier).saveToFirestore();
    // saveToFirestore 내부에서 _localImagePath 있으면 그때 업로드 + URL 저장
    ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('저장완료')));
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('저장실패: $e')));
  }
} : null,

 

4) ViewModel 핵심 로직

class UserViewModel extends Notifier<UserModel> {
  String? _localImagePath;
  String? get localImagePath => _localImagePath;

  void setLocalImagePath(String path) {
    _localImagePath = path; // 미리보기 전용
  }

  Future<void> saveToFirestore() async {
    // (이름/주소 등 유효성 체크)
    var current = state;
    if (current.id.isEmpty) {
      final newId = FirebaseFirestore.instance.collection('User').doc().id;
      current = current.copyWith(id: newId);
    }

    // 여기서만 실제 업로드
    if (_localImagePath != null && _localImagePath!.isNotEmpty) {
      final url = await ref.read(storageRepositoryProvider)
        .uploadUserProfile(userId: current.id, file: File(_localImagePath!));
      current = current.copyWith(img: url);
      _localImagePath = null; // 소모 완료
    }

    state = current;
    await ref.read(userRepositoryProvider).createOrUpdateUser(current);
  }
}

 

점검 포인트

 

  • 선택 핸들러에 upload... 호출이 남아있지 않은지 확인.
  • 미리보기는 로컬 경로만 사용하도록 조건 분기.
  • saveToFirestore() 안에서만 _localImagePath를 소비(업로드 후 null).

 

 

빠른 테스트

 

  1. 앱 실행 → 이미지 선택 → Storage에 새 파일 생기지 않아야 함.
  2. 이름/주소 입력 → ‘시작하기’ 클릭 → 그 시점에만 Storage 업로드 + Firestore URL 저장.
  3. 다시 들어와도 프로필 URL이 있으면 네트워크 이미지가 로드되는지 확인.