guricode

Riverpod ref.listen 라이프사이클 에러 트러블슈팅 본문

앱/Flutter&Dart

Riverpod ref.listen 라이프사이클 에러 트러블슈팅

agentrakugaki 2025. 10. 9. 13:35

코드를 짜다 보니 ref.listen을 initState() 안에 넣어뒀는데, 이게 문제였다.
ref.listen은 Riverpod이 위젯을 빌드하는 중에만 호출할 수 있는데,
initState()는 위젯이 아직 빌드 트리에 올라가기 전이라 Provider랑 연결이 안 돼 있다.
그래서 실행하자마자 아래 오류가 터졌다.

ref.listen can only be used within the build method of a ConsumerWidget
Failed assertion: 'debugDoingBuild'

결국 정리하자면

“빌드 전에 ref.listen을 불러서 Riverpod이 감시 대상을 찾을 수 없었던 것”

즉, 위젯이 완전히 만들어지기 전에 감시를 걸어서 생긴 구조적인 오류였다.

 

아래처럼 initState 안에서 ref.listen을 등록한 코드가 문제였다.

@override
void initState() {
  super.initState();

  // ❌ 빌드 전에 ref.listen 호출
  ref.listen<CommunityCreateVm>(
    communityCreateVmProvider,
    (prev, next) {
      // 상태 변경 시 동작
    },
  );
}

이 코드는 컴파일은 되지만 실행 도중 Flutter가
“아직 빌드 중이 아니야”라며 에러를 던진다.

해결 과정

ref.listen을 build() 안으로 옮기고,
UI 업데이트가 프레임 중에 일어나지 않도록
WidgetsBinding.instance.addPostFrameCallback으로 감쌌다.

이렇게 하면 위젯이 다 그려진 다음 컨트롤러나 선택 칩을 안전하게 갱신할 수 있다.

@override
Widget build(BuildContext context) {
  //  빌드 중에 ref.listen 등록
  ref.listen<CommunityCreateVm>(
    communityCreateVmProvider,
    (prev, next) {
      if (next.isEdit && !next.loading) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          if (_titleController.text != next.title) {
            _titleController.text = next.title;
          }
          if (_contentController.text != next.content) {
            _contentController.text = next.content;
          }
          // 카테고리 칩도 같이 반영
          ref.read(selectedCategoryCodeProvider.notifier).state =
              next.categoryCode;
          ref.read(selectedSubCategoryCodeProvider.notifier).state =
              next.categoryDetailCode;
        });
      }
    },
  );

  final st = ref.watch(communityCreateVmProvider);

  return Scaffold(
    appBar: AppBar(title: Text(st.isEdit ? '글 수정' : '글쓰기')),
    body: TextField(controller: _titleController),
  );
}

 

 

구분 잘못된 방식 수정한 방식

호출 위치 initState() build() 내부
호출 시점 위젯 초기화 중 위젯 빌드 중
UI 반영 시점 즉시 반영 (충돌 위험) addPostFrameCallback 으로 프레임 이후 반영
결과 debugDoingBuild 에러 발생 정상 작동 및 상태 동기화 완료

결론적으로

ref.listen은 빌드 중에만 쓸 수 있고,
컨트롤러나 칩 같은 UI 요소는 프레임이 끝난 뒤에 반영해야 한다.