Share
Embed
Transcript
26 slides
-
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 -
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! -
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. -
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'; } -
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. -
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); } -
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 -
Future Provider @riverpod Future<User> fetchUser(FetchUserRef ref, {required int userId}) async
{ final json = await http.get('api/user/$userId'); return User.fromJson(json); } -
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]; } } -
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(); }); } } -
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. -
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); } } -
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(), ), ); } } -
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(); } } -
Combining provider states @riverpod String city(CityRef ref) => 'London'; @riverpod
Future<Weather> weather(WeatherRef ref) { final city = ref.watch(cityProvider); return fetchWeather(city: city); } -
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 -
Install the dependencies $flutter pub add \ flutter_riverpod \ riverpod_annotation
\ dev:build_runner \ dev:riverpod_generator -
Watch and re-generate the code # Before starting coding $flutter
pub run build_runner watch Build Runner Extension -
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. -
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!