Riverpod - ref.watch and ref.read

After learning about how you could get the ref object to read providers, now is the time to understand how we can read or watch for our providers.

Difference between ref.watch and ref.read

You may think that if you want to read your providers you simply have to use always ref.read and the problem is solved, but it is not the case.

Basically ref.watch it is used to read your providers, but not only that, cause ref.watch allow you to listen to this provider when the state changes, this will rebuild and re render all the connected widgets;

That means, if you have a Text widget that read the value from StateProvider, if you change this provider you will see that the Text will magically transform to the new value, just like you have used setState.

You have to note that this happens even if you are using a ConsumerWidget (  replacement of StatelessWidget).

ref.read in the other hand it is used only to read, but, you should always prefer ref.watch even when you want to read.

Ref.read to Read

Ref.read is used to read our providers, that means that your read a value and even if the state of that provider change, the changes will be not reflected on the view.

It may seem strange but you should always prefer to use ref.watch instead of ref.read, there is also another way to read providers even with watch.

To use ref.read is pretty simple, you just to have to call your Provider by accessing .notifier or .state to get the controller.

NOTE: Using .notifier and .state to access the controller is the same thing.

Ref.read must be used on callbacks, like when you assign a function to a onPressed here is an example.

dart
final myProvider = StateProvider((ref) => 0);

IconButton(
	onPressed: () {
    	ref.read(myProvider.notifier).state++; <--- HERE
    },
	icon: const Icon(Icons.add),
),

In our case che .notifier to access the controller, then with the controller we access the state with .state; Here we will have the current value of our provider the number 0 but we then do ++ to increment by one the state.

Ref.watch to Watch for changes

Ref.watch is used to watch your providers, this means that when the state of your provider change you will get the updated value, if you are using any widget or condition related to this provider will get rerendered with the correct values.

We simply use ref.watch by calling the watch method present inside our ref, inside we pass our provider.

dart
final counterProvider = StateProvider((ref) => 0);

Widget build(BuildContext context, WidgetRef ref) {
  StateController<int> counter = ref.watch(counterProvider);
  
  return Center(
  	child: Text($counter),
  )
}

As explained previously ref.watch is also used to read providers when you are outside callbacks.

Don't use ref.read to improve performance

It is a bad practice to use ref.read always, cause you may think that by using ref.read you widget will not rebuild everytime hence your widget will perform better, but it is a bad practice as suggested by the author of the Riverpod package.

Instead of using ref.read you should do another thing, you should use ref.watch with a slight modification!

I took this example from the documentation:

dart
final counterProvider = StateProvider((ref) => 0);

Widget build(BuildContext context, WidgetRef ref) {
  // ".notifier" subscribes to the StateController instance but does
  // not rebuild the widget if its state changes
  StateController<int> counter = ref.watch(counterProvider.notifier);
  
  return ElevatedButton(
    onPressed: () => counter.state++,
  )
}

The modification is that you call the notifier property when using your provider; As I said previously you use ref.watch, in this way ref.watch will behave exactly like a read, it will not rebuild if things change.

how to read providers with riverpod how to use ref.watch and ref.read riverpod how to use ref.watch riverpod how to use ref.read how to use riverpod to read watch providers with riverpod riverpod tutorial to read providers
Expand your knowledge about this topic