주요 콘텐츠로 건너뛰기

왜 Riverpod인가?

Riverpod 이란?

Riverpod (Provider의 애너그램-철자를 바꾼 말)는 Flutter/Dart를 위한 반응형 캐싱 프레임워크(Reactive caching framework)입니다.

선언적 프로그래밍과 반응형 프로그래밍을 사용하는 Riverpod은 애플리케이션 로직의 상당 부분을 대신 처리해 줍니다. 내장된 오류 처리 및 캐싱 기능으로 네트워크 요청을 수행하는 동시에 필요한 경우 데이터를 자동으로 다시 가져올 수 있습니다.

Motivation

현대 애플리케이션은 UI를 렌더링하는 데 필요한 모든 정보를 제공하지 않습니다. 대신, 서버에서 비동기적으로 데이터를 가져오는 경우가 많습니다.

문제는 비동기 코드를 사용하는 것이 어렵다는 것입니다. Flutter는 상태 변수를 생성하고, 변경시 UI를 갱신하는 몇 가지 방법을 제공하지만, 아직은 상당히 제한적입니다.

  • 비동기 요청은 UI가 업데이트될 때마다 다시 실행하는 것은 불합리하므로 로컬에 캐시해야 할 필요가 있습니다.
  • 캐시가 있기 때문에 우리가 조심하지 않으면 오래된 상태가 될 수 있습니다.
  • 또한 오류 및 로딩 상태를 처리해야 합니다.

이러한 문제를 대규모로 해결하는 것은 어려울 수 있으며, 다음과 같은 많은 기능에 영향을 받습니다:

  • 당겨서 새로 고침
  • 무한 목록 / 스크롤할 때 가져오기
  • 타이핑하는 동안 검색
  • 비동기 요청의 디바운싱(Debouncing)
  • 더 이상 사용되지 않을 때 비동기 요청 취소
  • 낙관적(Optimistic) UI
  • 오프라인 모드
  • ...

이러한 기능은 구현하기 어려울 수 있지만, 좋은 사용자 경험을 위해 중요합니다. 아직까지 이러한 문제를 직접 해결하려는 패키지는 몇 개 없으며, 직접처리하려면 많은 작업이 필요합니다.

그래서 Riverpod이 등장했습니다. Riverpod은 Flutter 위젯에서 영감을 받아, 비즈니스 로직을 작성하는 새롭고 독특한 방식을 제공하여 이러한 문제를 해결하려고 합니다. 여러 가지 면에서 Riverpod은 위젯과 비슷하지만, 상태를 처리하기 위한 것입니다.

이 새로운 접근 방식을 사용하면, 복잡한 기능을 대부분 기본적으로 처리할 수 있습니다. 남은 것은 UI에 집중하는 것입니다.

아직 의심스러운가요? 여기 예시가 있습니다. 다음 스니펫은 Riverpod을 사용하여 구현된 Pub.dev 클라이언트 어플리케이션의 단순화 버전입니다.


// pub.dev에서 패키지 목록을 가져옵니다.

Future<List<Package>> fetchPackages(
Ref ref, {
required int page,
String search = '',
}) async {
final dio = Dio();
// API를 호출합니다. 여기서는 package:dio를 사용하고 있지만 다른 것을 사용할 수도 있습니다.
final response = await dio.get<List<Object?>>(
'https://pub.dartlang.org/api/search?page=$page&q=${Uri.encodeQueryComponent(search)}',
);

// JSON 응답을 Dart 클래스로 디코딩합니다.
return response.data?.map(Package.fromJson).toList() ?? const [];
}

이 스니펫은 당신이 에러/로딩 상태를 다루면서, "타이핑하는 동안 검색" + "당겨서 새로 고침" + "무한 목록"을 구현하는 데 필요한 모든 비즈니스 로직을 담고 있습니다.