카테고리 없음

Firestore CRUD 완성 및 Riverpod–Freezed–Hook 기반 구조 리팩토링

kwontete 2025. 11. 12. 10:17

[트러블 슈팅 ①] — Firestore CRUD 구현 중 데이터 조회(docs) 자동완성 오류

[상황 인지]

Firestore에서 Todo 목록을 조회하는 getToDos() 작성 중
querySnapshot.docs 부분에서 자동완성이 인식되지 않고
타입 불일치 오류가 발생했다.

 
final querySnapshot = db.collection('Todos').get(); // ← await 누락 final todos = querySnapshot.docs.map(...); // docs 인식 안 됨

[고민]

  • docs 속성이 인식되지 않는 이유는?
  • Firestore 문서(QuerySnapshot)의 반환 타입 문제인가?
  • 혹시 비동기 처리가 누락되어서 Future<QuerySnapshot>을 그대로 받고 있는 건 아닐까?

[적용]

  • await 키워드 누락 확인 → Future<QuerySnapshot>을 QuerySnapshot으로 동기 변환.
  • 아래처럼 수정함으로써 docs 접근 가능해짐:
 
final querySnapshot = await db.collection('Todos').get(); final todos = querySnapshot.docs.map((doc) => ToDoModel.fromJson(doc.data())).toList();

[결과]

  • Firestore 데이터 정상 조회 성공
  • CRUD (add(), get(), update(), delete()) 기능 전체 정상 작동
  • 전체 데이터 흐름이 Repository–ViewModel–UI로 잘 연결됨

[배운 점]

  • Firestore의 모든 CRUD 메서드는 Future를 반환하므로 await 필수
  • 단순한 IDE 경고라도 비동기 구조를 이해해야 근본 해결 가능
  • Repository–ViewModel–UI 계층 분리가 유지보수성 향상에 결정적

[트러블 슈팅 ②] — Freezed, Riverpod, Hook 적용 과정

[상황 인지]

Todo 앱 구조를 Freezed + Riverpod + Hook으로 리팩토링하면서
다음과 같은 복합 오류 발생:

  • The named parameter 'id' is required, but there's no corresponding argument.
  • Missing concrete implementations of getter ...
  • Map<String, dynamic> ↔ Map<String, Object> 타입 불일치
  • Hook 적용 중 (_) => 관련 문법 오류

[고민]

  • Freezed 사용 시 getter 관련 에러의 원인은?
    → part 'file.freezed.dart'; 또는 build_runner 미실행,
    혹은 잘못된 타입(Map<String, dynamic>)으로 선언된 필드 때문.
  • Hook 문법 오류((_) =>)는 불필요한 매개변수가 포함된 콜백이 원인.
  • StatefulWidget → HookConsumerWidget 전환 과정에서
    상태값 접근 방식(.value) 혼동으로 런타임 오류 발생.

[적용]

Freezed 모델 수정

  • @freezed 어노테이션 및 part 파일 정확히 선언
  • Map<String, Object?>로 타입 일원화
  • flutter pub run build_runner build --delete-conflicting-outputs 재실행

ViewModel 수정

  • 기존 수동 객체 수정 → copyWith 활용
  • toggleFavorite, toggleDone 시 불변 객체 복제 방식으로 변경

Hook 적용

  • StatefulWidget → HookConsumerWidget 구조로 리팩토링
  • useState, useTextEditingController, useFocusNode 적용
  • setState() 제거 및 .value 활용으로 상태 제어
  • 잘못된 (_) => 콜백 제거, 블록 구조 {}로 수정

[결과]

  • Freezed + Riverpod + Hook 구조 완전 안정화
  • 비동기 ViewModel과 Repository 간 연결 완성
  • dispose() 제거 → 리소스 자동 관리
  • UI 상태 반응성이 개선되고, 유지보수가 용이해짐

[배운 점]

  • Freezed는 불변성 + 코드 자동화를 동시에 제공
  • Riverpod AsyncNotifier는 상태 관리의 핵심이 ‘state 재할당’임을 체득
  • Hook으로 setState() 없는 반응형 UI 구현 가능
  • 각 프레임워크의 문법적 규칙을 정확히 이해하면 연결 시 오류 최소화

오늘의 핵심 정리

주제핵심 키워드요약
Firestore CRUD .add(), .get(), .update(), .delete() 모든 CRUD는 이 4개로 구성
Repository 패턴 Firestore 통신 분리 ViewModel과 UI에서 데이터 접근 단순화
AsyncNotifier state 재할당 구조 로딩, 데이터, 에러 상태를 명확히 구분
Freezed 불변 객체 + copyWith 유지보수성과 안정성 강화
Hook useState, useTextEditingController setState() 제거, 간결한 상태 관리

한줄 소감

오늘은 Firestore의 CRUD 흐름과
Freezed–Riverpod–Hook 구조의 연결 방식을 완벽히 이해했다.
단순히 동작만이 아니라 비동기 처리, 불변 데이터, 상태 재할당의 원리를 명확히 체득한 하루였다.