select<T, R> method
- R selector(
- T value
Watch a value of type T
exposed from a provider, and listen only partially
to changes.
select must be used only inside the build
method of a widget.
It will not work inside other life-cycles, including State.didChangeDependencies.
By using select, instead of watching the entire object, the listener will
rebuild only if the value returned by selector
changes.
When a provider emits an update, it will call synchronously all selector
.
Then, if they return a value different from the previously returned value, the dependent will be marked as needing to rebuild.
For example, consider the following object:
class Person with ChangeNotifier {
String name;
int age;
// Add some logic that may update `name` and `age`
}
Then a widget may want to listen to a person's name
without listening
to its age
.
This cannot be done using context.watch
/Provider.of
. Instead, we
can use select, by writing the following:
Widget build(BuildContext context) {
final name = context.select((Person p) => p.name);
return Text(name);
}
It is fine to call select
multiple times.
Implementation
R select<T, R>(R Function(T value) selector) {
assert(widget is! SliverWithKeepAliveWidget, '''
Tried to use context.select inside a SliverList/SliderGridView.
This is likely a mistake, as instead of rebuilding only the item that cares
about the selected value, this would rebuild the entire list/grid.
To fix, add a `Builder` or extract the content of `itemBuilder` in a separate widget:
```dart
ListView.builder(
itemBuilder: (context, index) {
return Builder(builder: (context) {
final todo = context.select((TodoList list) => list[index]);
return Text(todo.name);
});
},
);
```
''');
assert(widget is LayoutBuilder || debugDoingBuild, '''
Tried to use `context.select` outside of the `build` method of a widget.
Any usage other than inside the `build` method of a widget are not supported.
''');
final inheritedElement = Provider._inheritedElementOf<T>(this);
try {
final value = inheritedElement.value;
assert(() {
_debugIsSelecting = true;
return true;
}());
final selected = selector(value);
dependOnInheritedElement(
inheritedElement,
aspect: (T newValue) => !const DeepCollectionEquality()
.equals(selector(newValue), selected),
);
return selected;
} finally {
assert(() {
_debugIsSelecting = false;
return true;
}());
}
}