Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
Tags
- printf
- DART
- ListView
- java 출력
- lifecycle
- 엡
- 배포
- JS
- println
- JQ
- npm
- 자바 출력 방식
- UI/UX
- riverpod
- scss
- LLM
- nodejs
- 자바 포맷 출력
- firebase
- react
- 단축키
- unity
- 앱심사
- java 콘솔 출력 차이
- java
- Flutter
- 자바스크립트
- abap
- Clean Architecture
- develop
Archives
- Today
- Total
guricode
트러블슈팅: “프로필 이미지 선택만 했는데 바로 서버에 업로드됨” 본문
증상
- 갤러리에서 이미지를 선택만 했는데, 바로 Firebase Storage에 업로드되고 Firestore에도 URL이 저장됨.
- 의도는 ‘시작하기’ 버튼을 눌렀을 때만 업로드/저장.
원인
- 이미지 선택 핸들러(_pickAndUpload)에서 업로드 메서드를 바로 호출함.
- 그래서 다른 요소(이름,지역설정)을 설정 안했는데도 파이어스토어에 이미지가 업로드돼어버림
// 문제 코드
final picked = await picker.pickImage(...);
if (picked == null) return;
await ref.read(userViewModelProvider.notifier)
.uploadAndSaveProfileImage(File(picked.path)); // ← 즉시 업로드
해결 전략
- 선택 시점에는 업로드 금지, 로컬 경로만 상태에 보관(미리보기 용).
- ‘시작하기’ 버튼에서만 업로드 + 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).
빠른 테스트
- 앱 실행 → 이미지 선택 → Storage에 새 파일 생기지 않아야 함.
- 이름/주소 입력 → ‘시작하기’ 클릭 → 그 시점에만 Storage 업로드 + Firestore URL 저장.
- 다시 들어와도 프로필 URL이 있으면 네트워크 이미지가 로드되는지 확인.
'앱 > Flutter&Dart' 카테고리의 다른 글
| Flutter ThemeExtension (2) | 2025.08.18 |
|---|---|
| Flutter Firebase 시작 정리 - 설치부터 초기화까지 (3) | 2025.08.14 |
| Flutter iOS 시뮬레이터에서 위치 테스트하는 방법 (3) | 2025.08.11 |
| Flutter SDK 버전 오류 트러블슈팅: Dart SDK 버전 불일치 (1) | 2025.08.08 |
| 트러블슈팅: CircleAvatar로 프로필 이미지 UI 구현 시 크기 제약 문제 (0) | 2025.08.07 |