$30 off During Our Annual Pro Sale. View Details »

April Flutter Meetup - Riverpod Introduction

GDG Montreal
April 18, 2023
72

April Flutter Meetup - Riverpod Introduction

GDG Montreal

April 18, 2023
Tweet

Transcript

  1. Riverpod
    Introduction
    Jhin Lee
    Full-Stack Developer
    Unity

    View Slide

  2. 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

    View Slide

  3. 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!

    View Slide

  4. 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.

    View Slide

  5. 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';
    }

    View Slide

  6. 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.

    View Slide

  7. Code generation - Examples
    // Without code generation
    final fetchUserProvider = FutureProvider.autoDispose.familyString>((ref, userId) async {
    final json = await http.get('api/user/$userId');
    return User.fromJson(json);
    });
    // With code generation
    @riverpod
    Future fetchUser(FetchUserRef ref, {required int userId}) async {
    final json = await http.get('api/user/$userId');
    return User.fromJson(json);
    }

    View Slide

  8. 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

    View Slide

  9. Basic Provider
    @riverpod
    Repository repository(RepositoryRef ref) {
    return Repository();
    }

    View Slide

  10. Future Provider
    @riverpod
    Future fetchUser(FetchUserRef ref, {required int userId})
    async {
    final json = await http.get('api/user/$userId');
    return User.fromJson(json);
    }

    View Slide

  11. NotifierProvider
    @riverpod
    class Todos extends _$Todos {
    @override
    List build() {
    return [];
    }
    // Let's allow the UI to add todos.
    void addTodo(Todo todo) {
    state = [...state, todo];
    }
    }

    View Slide

  12. AsyncNotifierProvider
    @riverpod
    class AsyncTodos extends _$AsyncTodos {
    Future> _fetchTodo() async {
    final todos = jsonDecode(await http.get('api/todos')) as Listdynamic>>;
    return todos.map(Todo.fromJson).toList();
    }
    @override
    FutureOr> build() async => _fetchTodo();
    Future addTodo(Todo todo) async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
    await http.post('api/todos', todo.toJson());
    return _fetchTodo();
    });
    }
    }

    View Slide

  13. 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.

    View Slide

  14. 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);
    }
    }

    View Slide

  15. 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(),
    ),
    );
    }
    }

    View Slide

  16. 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(counterProvider, (int? previousCount, int newCount) {
    print('The counter changed $newCount');
    });
    return Container();
    }
    }

    View Slide

  17. Combining provider states
    @riverpod
    String city(CityRef ref) => 'London';
    @riverpod
    Future weather(WeatherRef ref) {
    final city = ref.watch(cityProvider);
    return fetchWeather(city: city);
    }

    View Slide

  18. 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

    View Slide

  19. How to install

    View Slide

  20. Install the dependencies
    $flutter pub add \
    flutter_riverpod \
    riverpod_annotation \
    dev:build_runner \
    dev:riverpod_generator

    View Slide

  21. Wrap the entry widget with ProviderScope
    void main() {
    runApp(ProviderScope(child: MyApp()));
    }

    View Slide

  22. Watch and re-generate the code
    # Before starting coding
    $flutter pub run build_runner watch
    Build Runner
    Extension

    View Slide

  23. Demo - Todo app
    GitHub

    View Slide

  24. 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.

    View Slide

  25. 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!

    View Slide

  26. Thanks!

    View Slide