Why Choose Riverpod? - Accessing the Providers

Why Choose Riverpod? - Accessing the Providers

This post is based off a presentation I did at Devfest 2023 in Cape Town on 23 Nov 2023. VIDEO | PRESENTATION


Previously we covered the extension methods provided by Riverpod, in this post we will take look at how we access these providers


UI

Some of you. may have notice the two references to "ref" in the examples in the previous parts of this series, similar to build context, that is how Riverpod accesses its providers. On the UI side you will have a WidgetRef and within a Riverpod Provider you will simply use Ref.

For the UI side we simply need to replace the StatelessWidget with the ConsumerWidget which will then add the WidgetRef as the second argument on the widgets build method, from there we have access to many of the same accessors we would use with Provider or BLoC/Cubit. There is also a StatefulConsumer widget as well as Hook versions available in a separate package for those who make use of flutter_hooks.

// UI Side
class Widget extends ConsumerWidget {
    Widget build(BuildContext context, WidgetRef ref) {
      final read = ref.read(operationsProvider(task.id));

      final watch = ref.watch(operationsProvider(task.id));

      final select = ref.watch(
        operationsProvider(task.id)
          .select((v) => v.first
      );

      final (first, second) = ref.watch(
        operationsProvider(task.id).select(
          (v) => (v.first, v.second),
        ),
      );
    }
}

For those not familiar, we have the read which is used simply for accessing data from the provider, something which is advised against in the context of a widget as naturally any changes to the data will be ignored, so be careful when choosing to go this route and making sure the UI does not need to respond to changes.

watch is, as the name suggest, a listener on the state and will trigger a rebuild whenever any piece of data within that state updates allowing the UI to reflect any of those changes.

Along with the watch we also have the ability to use select which will allow us to scope which values within the state the listener responds to. This provides a lot more control over what triggers the widget to redraw which can be handy in larger states and help with performance.

Classes

When it comes to accessing providers form within another provider, it is even more straightforward, here you would always be using read which is accessed from the Ref that is available within all Riverpod Providers.

class SharedNotifier extends StateNotifier<SharedState> {
  final Ref ref;
  final String id;

  SharedNotifier(this.ref, this.id) : super(SharedState.initial());

  Future<void> updateTaskStatus(TaskStatus status) async {
    ref.read(sampleNetworkProvider)
      ..updateFlows(state.task, true, type)
      ..updateFlowStatus(state.order, status, type);
  }
}

In the above code we are accessing one of our network providers and chaining a couple of methods onto that in order to fire off a set of API calls to update the status of the currently active task.


Next we will take a look at ProviderScope the Riverpod widget that gives us most of it super powers.


I hope you found this interesting, and if you have any questions, comments, or improvements, feel free to drop a comment. Enjoy your development journey :D

Thanks for reading.