Let’s take, for example, the State<StatefulWidget>
. When you need to know if the widget is mounted, you just ask if(context.mounted)
.
If you check the signature of BuildContext
, you’ll see that it is a property:
bool get mounted;
This (almost always) means that reading this value is fast to be read and there isn’t work being done to compute it.
Now, compare with MediaQuery.sizeOf(context)
:
First, it will call a InheritedModel
(not an InheritedWidget
):
static Size sizeOf(BuildContext context) => _of(context, _MediaQueryAspect.size).size;
Then the rabbit goes down the hole until it reaches this method (don’t worry in trying to read or understand it):
static T? inheritFrom<T extends InheritedModel<Object>>(BuildContext context, {Object? aspect}) {
if (aspect == null) {
return context.dependOnInheritedWidgetOfExactType<T>();
}
// Create a dependency on all of the type T ancestor models up until
// a model is found for which isSupportedAspect(aspect) is true.
final List<InheritedElement> models = <InheritedElement>[];
_findModels<T>(context, aspect, models);
if (models.isEmpty) {
return null;
}
final InheritedElement lastModel = models.last;
for (final InheritedElement model in models) {
final T value = context.dependOnInheritedElement(model, aspect: aspect) as T;
if (model == lastModel) {
return value;
}
}
assert(false);
return null;
}
}
Notice how complex this is. The important part here is that _findModels
call:
static void _findModels<T extends InheritedModel<Object>>(
BuildContext context,
Object aspect,
List<InheritedElement> results,
) {
final InheritedElement? model = context.getElementForInheritedWidgetOfExactType<T>();
if (model == null) {
return;
}
results.add(model);
assert(model.widget is T);
final T modelWidget = model.widget as T;
if (modelWidget.isSupportedAspect(aspect)) {
return;
}
Element? modelParent;
model.visitAncestorElements((Element ancestor) {
modelParent = ancestor;
return false;
});
if (modelParent == null) {
return;
}
_findModels<T>(modelParent!, aspect, results);
}
Notice that this is a recursive function! It will go up the tree trying to find the first occurence of your InheritedModel
(in this example, the MediaQuery.sizeOf
).
That’s the main difference between properties and methods: usually, properties are safe to read and they don’t do almost any job, while methods can be very nasty, such as this one.
So, as a rule, whenever you need to get the value of something that you can use in two or more places (such as Theme.of(context)
), it’s always wise to cache it: final theme = Theme.of(context)
.