본문 바로가기
프로그래밍/Flutter <Dart>

[Flutter] Riverpod AsyncNotifierProvier 활용해서 비동기 데이터 가져오기

by TaeGyeong Lee 2025. 12. 27.

Riverpod 을 활용, 비동기로 외부 데이터를 가져오는 방법을 서술합니다. 

NOTE: Riverpod 플러그인이 설치되어 있음을 가정합니다. 없다면 설치해 주세요. 

Riverpod에서 제공하는 provider는 다양합니다. 사용 의도에 맞게 골라 사용할 수 있도록 세분화 되어있습니다. 공부하는 입장에선 좀 피곤하긴 합니다. 이 글에선 AsyncNotifierProvider를 사용합니다. 

6개나 되는 Provider들

 

Notifier 

Notifier는 수정 가능한 상태를 노출하는 클래스입니다. 수정이 필요없다면 Notifier를 선언할 필요가 없습니다. 

AsyncNotifier

AsyncNotifier는 초기화 이후에도 추가적으로 값을 업데이트할 수 있습니다. 데이터를 추가로 가져오고 업데이트할 경우를 감안하여 AsyncNotifier를 사용하겠습니다.

 

AsyncNotifier 정의 

  • 이 AsyncNotifier의 초기값은 'abcedfg'입니다. 
class stringNotifier extends AsyncNotifier<String> {
  @override
  String build() {
    return 'abcdefg';
  }

  Future<String> fetchString() async {
    try {
      // 로딩 상태로 설정
      state = const AsyncValue.loading();

	  // 데이터 패칭 
      fetchStringData = ... 
      
      // 성공 시 state 업데이트
	  state = AsyncValue.data(fetchStringData);
	  return fetchStringData;
    } catch (e, st) {
      state = AsyncValue.error(e, st);
      rethrow;
    }
  }
}

 

AsyncNotifierProvider 생성 

위에서 만든 AsyncNotifier를 AsyncNotifierProvider로 생성해 보겠습니다. 이름 참 깁니다. 

생성 

// provider 생성
final stringProvider = AsyncNotifierProvider<stringNotifier, String>(
  stringNotifier.new, // 예제에 따라 'abcdefg'가 될 것임
);

코드에 별 내용이 없죠? 이럴 거면 Provider가 왜 필요하냐 싶으실 텐데, Provider는 기본적으로 필요하고, 이 예제를 구현하기 위해 Notifier를 추가로 만든다고 보셔야 합니다. 

AsyncNotifier인 stringNotifier 클래스를 기반으로 AsnycNotifierProvider객체가 생성되었습니다. 이름 참 기네요. 

 

Consumer 위젯 생성

Consumer 

Consumer는 Provider를 활용할 수 있는 위젯입니다. provider를 활용하기 위해 ref 라는 파라미터를 추가로 받습니다. ref 파라미터를 통해서 provider를 활용할 수 있습니다. 

  • Consumer
  • ConsumerWidget
  • ConsumerStatefulWidget

이 제공되며, 취향에 따라 선택하면 됩니다. 저는 ConsumerWidget을 사용하겠습니다. 

NOTE: Consumer 와 ConsumerWidget 중 고민한다면 ConsumerWidget을 사용하세요. Consumer는 ConsumerWidget을 그대로 상속받은 위젯입니다. 실제 개발에서 쓸 이유가 별로 없어요. 

 

ConsumerWidget vs ConsumerStatefulWidget 

ConsumerWidget은 StatelessWidget 과 '비슷'하고, ConsumerStatefulWidget은 StatefulWidget과 비슷합니다. 

NOTE: ConsumerWidget은 ConsumerStatefulWidget을 상속받습니다. 이상하죠? 개발 의도는 StatelessWidget '처럼' 쓰기 위함입니다. 실제론 동일하지 않습니다. ConsumerWidget이든, ConsumerStatefulWidget이든 StatefulWidget입니다. 

<< 위젯 간 상속 구조 >> 

StatefulWidget
    ↓
ConsumerStatefulWidget
    ↓
ConsumerWidget
    ↓
Consumer

 

watch 

build 함수 내에 AsyncValue 생성합니다. ref 를 활용해서 이전에 생성한 stringProvider를 지켜보겠습니다. 

class stringConsumerWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) { // 다른 위젯과 다르게 WidgetRef 타입을 받음 
    final AsyncValue stringProviderValue = ref.watch(stringProvider); // AsyncValue 생성 

    return Text('a');
    }
}

NOTE: watch vs listen 의 차이는 이 글을 참고하세요. 이해하는데 많은 도움이 되었습니다. 

 

when 

이제 asyncValue를 사용하여 데이터 업데이트, 로딩을 감지하고 경우에 맞게 표기하겠습니다. 이때 asyncValue의 when을 사용하면 됩니다. asyncValue는 loading, error에 대한 상태를 활용할 수 있습니다. (Notifier 선언 코드 참고) 

stringProviderValue.when(
	data: (data) => 
    	Text('${data}'), // 데이터를 출력하는 부 
    loading: () => Center(child: CircularProgressIndicator()), // loading 상태일 때 출력하는 부
    error: (error, stackTrace) { } // 에러 상태일 때 출력하는 부
    )

 

참고 자료