rrousselGit / riverpod

A reactive caching and data-binding framework. Riverpod makes working with asynchronous code a breeze.
https://riverpod.dev
MIT License
6.26k stars 959 forks source link

ChangeNotifierProviders select() function does not match riverpod.dev and inline documentation #2795

Closed AlexProductions closed 1 year ago

AlexProductions commented 1 year ago

Describe what scenario you think is uncovered by the existing examples/articles The current documentation of provider.select() does not match in relation to ChangeNotifierProvider

The riverpod.dev docs say, using provider.select on ChangeNotifierProvider will not work, whereas the inline documentation of the function explicitly shows an example with the ChangeNotifierProvider

From Riverpod v2 Doc - ChangeNotifier

...
For example, using provider.select to optimize rebuilds of your widgets may not work if your state is mutable, as select will think that the value hasn't changed.
...

From Riverpod inline documentation of Package flutter_riverpod: ^2.3.6

...
The select function allows filtering unwanted rebuilds of a Widget by reading only the properties that we care about.
For example, consider the following ChangeNotifier:
...

The following are longer extractions of the Documentations mentioned above to faster get in context without needing to check the ressouces.

... from riverpod.dev v2 (link above):

Using mutable state instead of immutable state can sometimes be more efficient. 
The downside is, it can be harder to maintain and may break various features.
For example, using provider.select to optimize rebuilds of your widgets may not work if your state is mutable, as select will think that the value hasn't changed.
As such, using immutable data structures can sometimes be faster. 
Therefore it is important to make benchmarks specific to your use-case, to make sure that you are truly gaining performance by using ChangeNotifierProvider.

... Inline Documentation:

package:riverpod/src/framework.dart 
AlwaysAliveProviderListenable<Selected> select<Selected>(Selected Function(UserNotifier) selector)  

Containing class: AlwaysAliveProviderBase  
Type: AlwaysAliveProviderListenable<dynamic> Function(dynamic Function(UserNotifier))  

Partially listen to a provider.
The select function allows filtering unwanted rebuilds of a Widget by reading only the properties that we care about.
For example, consider the following ChangeNotifier:
class Person extends ChangeNotifier {
  int _age = 0;
  int get age => _age;
  set age(int age) {
    _age = age;
    notifyListeners();
  }

  String _name = '';
  String get name => _name;
  set name(String name) {
    _name = name;
    notifyListeners();
  }
}

final personProvider = ChangeNotifierProvider((_) => Person());
In this class, both name and age may change, but a widget may need only age.
If we used ref.watch(/Consumer as we normally would, this would cause widgets that only use age to still rebuild when name changes, which is inefficient.
....
rrousselGit commented 1 year ago

The example given in the dartdoc of select works.

The issue with mutable state + select generally arises when returning a mutable object in the selector, such as a list.

provider.select((value) => value.someMutableList);

Then, when the list is mutated, providers wouldn't rebuild

rrousselGit commented 1 year ago

Closing as there's technically nothing wrong