Upgrade to Pro — share decks privately, control downloads, hide ads and more …

April Flutter Meetup - Riverpod Introduction

GDG Montreal
April 18, 2023
96

April Flutter Meetup - Riverpod Introduction

GDG Montreal

April 18, 2023
Tweet

Transcript

  1. Speaker - Jhin Lee • Full-Stack Developer @Unity ◦ Golang,

    JS/TS, React.js(Next.js), GCP • Full-Stack Developer @ConsiderBeyond ◦ Firebase + Flutter ◦ https://www.considerbeyond.com • LinkedIn: https://www.linkedin.com/in/leehack
  2. Agenda • What is Riverpod? • What is (Riverpod’s)Provider? •

    Code generation • Different kinds of providers ◦ Function Provider ◦ Class Provider • How to read a provider • How does provider works? • How to install • Todo App demo - Let’s code!
  3. What is Riverpod? • Author: Remi Rousselet ◦ Author of

    provider, freezed, and more. • riverpod (an anagram of provider) is a reactive caching framework for Flutter/Dart. • riverpod is a complete rewrite of the provider package to make improvements. • Catch errors at compile-time rather than at runtime.
  4. What is (Riverpod’s)Provider? • An object that encapsulates a state

    and allows listening to the changes. • Allows easily accessing to a state from multiple locations. • A replacement of patterns like Singletons, Service Locators, Dependency Injection, or InheritedWidgets. @riverpod String helloWorld(HelloWorldRef ref) { return 'Hello world'; }
  5. Code generation • Riverpod 2.0 supports code generation. • It

    automatically decides and creates the best provider for the use case. • Code generation is pretty common pattern in Flutter or Dart programming. • Static metaprogramming feature is coming to dart.
  6. Code generation - Examples // Without code generation final fetchUserProvider

    = FutureProvider.autoDispose.family<User, String>((ref, userId) async { final json = await http.get('api/user/$userId'); return User.fromJson(json); }); // With code generation @riverpod Future<User> fetchUser(FetchUserRef ref, {required int userId}) async { final json = await http.get('api/user/$userId'); return User.fromJson(json); }
  7. Different kinds of Providers Provider FutureProvider StreamProvider NotifierProvider AsyncNotifierProvider -

    New in 2.0 StateProvider - Legacy StateNotifierProvider - Legacy ChangeNotifierProvider - Legacy StreamNotifierProvider - New in 2.0 Function Provider Class Provider
  8. Future Provider @riverpod Future<User> fetchUser(FetchUserRef ref, {required int userId}) async

    { final json = await http.get('api/user/$userId'); return User.fromJson(json); }
  9. NotifierProvider @riverpod class Todos extends _$Todos { @override List<Todo> build()

    { return []; } // Let's allow the UI to add todos. void addTodo(Todo todo) { state = [...state, todo]; } }
  10. AsyncNotifierProvider @riverpod class AsyncTodos extends _$AsyncTodos { Future<List<Todo>> _fetchTodo() async

    { final todos = jsonDecode(await http.get('api/todos')) as List<Map<String, dynamic>>; return todos.map(Todo.fromJson).toList(); } @override FutureOr<List<Todo>> build() async => _fetchTodo(); Future<void> addTodo(Todo todo) async { state = const AsyncValue.loading(); state = await AsyncValue.guard(() async { await http.post('api/todos', todo.toJson()); return _fetchTodo(); }); } }
  11. How to read a provider • ref object is accessible

    from a widget or another provider. • ref.watch() to observe a provider change. ◦ It triggers rebuilding a widget or provider when it’s changed. • ref.listen() to react to a provider change. ◦ It calls the callback function registered when it’s changed. • ref.read() to obtain the state of a provider. ◦ It only read once. Whenever possible, prefer using ref.watch over ref.listen or ref.read to implement a feature. This way, the application becomes reactive and declarative.
  12. Rebuild with a state change @riverpod class Counter extends _$Counter

    { @override int build() => 0; void increment() => state = state + 1; } class HomeView extends ConsumerWidget { const HomeView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final count = ref.watch(counterProvider); return Text(count); } }
  13. Read the current state without observe @riverpod class Counter extends

    _$Counter { @override int build() => 0; void increment() => state = state + 1; } class HomeView extends ConsumerWidget { const HomeView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( floatingActionButton: FloatingActionButton( onPressed: () => ref.read(counterProvider.notifier).increment(), ), ); } }
  14. Listen to react to a state change @riverpod class Counter

    extends _$Counter { @override int build() => 0; void increment() => state = state + 1; } class HomeView extends ConsumerWidget { const HomeView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { ref.listen<int>(counterProvider, (int? previousCount, int newCount) { print('The counter changed $newCount'); }); return Container(); } }
  15. Combining provider states @riverpod String city(CityRef ref) => 'London'; @riverpod

    Future<Weather> weather(WeatherRef ref) { final city = ref.watch(cityProvider); return fetchWeather(city: city); }
  16. How does provider works? ref.watch(aProvider) aProvider ref.watch(aProvider) bProvider ref.watch(bProvider) Map(GlobalScope)

    Automatically Initialize the provider when the first time it’s watched Automatically Dispose the provider when there’s no watchers
  17. Watch and re-generate the code # Before starting coding $flutter

    pub run build_runner watch Build Runner Extension
  18. Home work! Here are some ideas to get familiarized with

    Riverpod. • Fork the demo app code. • Add the delete feature. • Add the edit feature. • Convert selectedFilter into Provider in todo_page.dart. • Share your achievements or get help from discord.
  19. Bonus! • Riverpod 2.0 documentation • Riverpod lint - Highly

    recommended! • Riverpod snippet extension for Visual Studio Code • Build runner extension for Visual Studio Code • Code with Andrea’s tutorial - Awesome tutorials!