Flutter Riverpod Latest Guide

Flutter Riverpod Latest Guide

    Riverpod 2.0 has big change then the earlier versions. It introduced auto generated providers which is convenient and less error prone. It has also introduced two new providers NotifierProvider and AsyncNotifierProvider.

    it also introduced another two new providers. Previous versions have seen six providers. You can still use the older version of Providers.

    In this new version NotifierProvider and AysncNotifierProvider are encouraged to use more. Since the new version depends a lot more on the auto generation of code, we will first see how to auto generate Providers with a package name

    riverpod_generator

    Go ahead and install the plugin. At the same time make sure you install riverpod latest version at least equal to 2.0 or above.

    Let's take an example. Previously we could have a Provider like below

    final stringLabelProvider = Provider<String>((ref) => 'Hello World');

    The above providers is manually typed in and you mention the provider type. Here we return a Provider which gives us a String.

    Annotation & function name

    Now we do the same using riverpod annotation. It's a special syntax. It's like below

    @riverpod

    With this Flutter would know that, it needs to generate riverpod code. But how does it do it ? You need to give it more information, you need to provide it with a function. 

    @riverpod
    String StringLabel(StringLabelRef ref)=>'Hello World of Riverpod';

    The above one is a function that would generate a Riverpod provider. See the annotation at the top. With this kind of syntax you don't need to mention the Providers you want. Riverpod will auto generate the Provider for you. All you need to do it mention the return type of the function

    In the above case, we need a Provider to manage our String. So Riverpod will auto generate a Provider that will help us manage a String. 

    Even though it looks like there's more code write this time, but this is still cool since you don't need to mention the Provider type on your own. Previously it was confusing to mention since there are six types of Providers.

    We are two more steps away from the auto generated code. You need to 

    mention where to put the auto generated provider code

    run a special command to generate the provider

    File path name

    You need to tell riverpod where to generate the file and you need to give it a name. The name should be similar as your current file name. 

    In this case our out function mentioned is in main.dart, so the auto generated file would be main.g.dart. You need mention at the top right below other imports.

    import 'package:riverpod_annotation/riverpod_annotation.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    import 'package:flutter/material.dart';
    part 'main.g.dart';

    You see we put the file name as part of our project and we put below other imports.

    Run command

    This is the last step. We need to run a command to auto generate the code. The is is given as below

    flutter pub run build_runner watch --delete-conflicting-outputs

    for the above command to run make sure you have installed the below plugin

    build_runner:

    After running command look at the file below.

    So now our main.dart looks like below

    import 'package:riverpod_annotation/riverpod_annotation.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    import 'package:flutter/material.dart';
    part 'main.g.dart';
    
    //final stringLabelProvider = Provider<String>((ref) => 'Hello World');
    
    @riverpod
    String StringLabel(StringLabelRef ref)=>'Hello World of Riverpod';
    
    void main() {
      runApp(ProviderScope(child: Home()));
    }
    
    class Home extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        return MaterialApp(
          home: Scaffold(
            body: Center(
              child: Text(
                ref.watch(stringLabelProvider),
                style: const TextStyle(fontSize: 30),
              ),
            ),
          ),
        );
      }
    }

    You will also see there's a main.g.dart in our lib folder. That file is scary, but you need to look at the bottom part of the file. 

    riverpod auto generate code providers

    You will see the above code in the bottom of the main.g.dart. Here's a provider that's been generated for us and it's stringLableProvider.

    The Provider stringLableProvider we used in our UI code.

    NotifierProvider

    This is a new provider, this one is supposed to replace ChangeNotifierProvider, StateNotifierProvider and StateProvider.

    Let's see how to use Riverpod 2.0 NotifierProvider for reactive state and change state of the app. Here we will first create a class and our class would extend Notifier. Here we will do everythign manully. You can still generate code using riverpod generator plugin

    With Notifier you need to mention your state variable type. In this case we will have a string and it should be reactive. so we will mention it.

    class NewStringLabel extends Notifier<String>{
      @override
      String build() {
        return 'dbestech';
      }
    
      void toCamelCase() {
        state = '${state[0].toUpperCase()}${state.substring(1).toLowerCase()}';
        print(state);
      }
    }

    Next we also have to override the build method. Build method should return String type since our Notifier return type is String. You may understand it the other way,

    Since build method returns String type, Notifier should return String too.

    At the same time, we have a method name toCamelCase(), we will call this method using our Provider.

    And after that we need to expose our state to the outside world.

    We will do that using NotifierProvider. NotifiterProvider would take our custom class and Notifer type.

    final newStringLabel = NotifierProvider<NewStringLabel, String>(NewStringLabel.new);
    

    Previously you would have done it using Provider, StateNotifierProvider or StateProvider.

    See the complete code for this example.

    class NewStringLabel extends Notifier<String>{
      @override
      String build() {
        return 'dbestech';
      }
    
      void toCamelCase() {
        state = '${state[0].toUpperCase()}${state.substring(1).toLowerCase()}';
        print(state);
      }
    }
    final newStringLabel = NotifierProvider<NewStringLabel, String>(NewStringLabel.new);
    
    void main() {
      runApp(ProviderScope(child: Home()));
    }
    
    class Home extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        return MaterialApp(
          home: Scaffold(
            body: Center(
              child: Consumer(
                builder: (context, ref, child) {
                  final String val = ref.watch(newStringLabel);
                  return ElevatedButton(onPressed: (){
                    ref.watch(newStringLabel.notifier).toCamelCase();
                  }, child: Text(val));
                },
              ),
            ),
          ),
        );
      }
    }

    If you have list of objects like custom objects, String or integer,  you may still use Notifier and NotifierProvider. Your Notifier may return list of objects. In our below example we return list of Strings. 

    class StringGenerator extends Notifier<List<String>>{
      @override
      List<String> build() {
        // TODO: implement build
        return [];
      }
    
      void addString(String randomStr){
        state = [...state, randomStr];
        print(state.length);
      }
    
      void removeAString(int index){
        state.removeAt(index);
        state = [...state];
      }
      void removeString(){
        state = [];
      }
    
    }
    
    var strNotifierProvider
    = NotifierProvider<StringGenerator, List<String>>(StringGenerator.new);

    Like in the code, we have addString(), removeAString() and removeString(). They all operate on Strings using state object.

    Our state object is held by Notifier class. And this notifier is exposed to the UI using NotifierProvider.

    Pass WidgetRef

    Say you have a controller and you need to pass WidgetRef object globally to the controller and use the context of the ref object? How would do it? Actually it's easy. Every controller needs to be initialized.

    Since controllers needs to be initialized, you may create a constructor of the controller and pass WidgetRef object from the UI and use it.

    See how I am initializing and passing the ref object to the controller. Now we would be able to grab the ref object in the controller.

    Let's see how to get it on the controller

    See how I accepted WidgetRef in the constructor, and use ref.context inside showDialog

    Courses


    Recent posts