본문으로 건너뛰기

소개


What is Riverpod?

Riverpod (anagram of Provider) is a reactive caching framework for Flutter/Dart. It can automatically fetch, cache, combine and recompute network requests, while also taking care of errors for you.

Motivation

Modern applications rarely come with all the information necessary to render their User Interface. Instead, the data is often fetched asynchronously from a server.

The problem is, working with asynchronous code is hard. Although Flutter comes with some way to store state, it doesn't do much besides that. Thus, a number of challenges remain unsolved:

  • Asynchronous requests need to be cached locally, as it would be unreasonable to re-execute them whenever the UI refreshes.
  • Since we have a cache, our cache could get out of date if we're not careful.
  • We also need to handle errors and loading states

Nailing those problems at scale can be difficult, and they are impacted by a large amount of features, such as:

  • pull to refresh
  • infinite lists / fetch as we scroll
  • search as we type
  • debouncing asynchronous requests
  • cancelling asynchronous requests when no-longer used
  • optimistic UIs
  • offline mode
  • ...

These features can be tricky to implement, but are crucial for a good user experience.
Yet few packages try to tackle those problems directly, and a lot of the work has to be done manually.

That's where Riverpod comes in.
Riverpod tries to solve those problems, by offering a new unique way of writing business logic, inspired by Flutter widgets. In many ways Riverpod is comparable to widgets, but for state.

Using this new approach, these complex features are mostly done by default. All that's left is to focus on your UI.

Skeptical? Here's an example. The following snippet is a simplification of the Pub.dev client application implemented using Riverpod.

// Fetches the list of packages from pub.dev

Future<List<Package>> fetchPackages(
FetchPackagesRef ref, {
required int page,
String search = '',
}) async {
final dio = Dio();
// Fetch an API. Here we're using package:dio, but we could use anything else.
final response = await dio.get(
'https://pub.dartlang.org/api/search?page=$page&q=${Uri.encodeQueryComponent(search)}',
);

// Decode the JSON response into a Dart class.
final json = response.data as List;
return json.map(Package.fromJson).toList();
}

This snippet is all the business logic you need for a "search as we type"

  • "pull to refresh" + "infinite list", while handling error/loading states.