This would be a very small patch.. e.g:
static T of<T>(BuildContext context, {bool listen = true, bool allowNull = false}) {
// ...
if (provider == null && !allowNull) {
throw /* ... */;
}
return provider?._value;
}
Yes, a provider being absent from the tree should be an error in most cases, but there are some times where you want to optionally provide something down to the rest of the tree. I've run into this multiple times when working with provider, and in some cases it's more useful to manually write an inherited widget.
I think bool nullOk = false is better than bool allowNull = false for consintency.
Flutter framework uses that term like this:
https://github.com/flutter/flutter/blob/2d2a1ffec95cc70a3218872a2cd3f8de4933c42f/packages/flutter/lib/src/material/scaffold.dart#L1256
There's a catch though: Soon, Dart will have non-nullable types.
A allowNull will not compile anymore. Maybe a secondary of method that allows null instead:
class Provider {
static T? maybeOf<T>(BuildContext context) { ... }
}
Alternatively, we can remove the exception and always make the result of .of nullable.
That'd be a breaking change (and pretty boring to use). But it's safer.
I like maybeOf a bit more. It'll get really weird with NNBD though, since you can have a provider that provides a nullable value.
What about doing return provider?._value as T;? Then the optionality is encoded in the type system, since this will throw an error at runtime.
I think you might also be able to test whether a type is nullable by doing if (null is T), so another alternative is to do:
static T of<T>(BuildContext context, {bool listen = true}) {
// ...
if (provider == null) {
if (null is T) {
return null;
} else {
throw /* ... */;
}
}
return provider?._value as T; // T? to T, if T is already nullable then T?? == T? which never fails
}
That'd cause a problem with non-nullable providers, while trying to handle the "there's no provider" scenario.
Consider the following NNBD snippet:
Provider<Model>(
builder: (_) => Model()),
child: ...
)
Then if we want to obtain Model while handling the "no provider" case, then we'd have to do:
Provider.of<Model?>(context)
The issue is, that won't work because Model is obtained through a runtimeType comparison. And Model != Model?, so no provider will ever be found.
It's probably an edge case though.
Ah yeah, would help if we could do ! on types too.
Ah yeah, would help if we could do
!on types too.
It's possible. But I don't see how that would help
Also, note that it's already feasible to handle such a scenario with a try catch.
@rrousselGit Not exactly, people who use strict lints against catching Errors will have to insert an // ignore comment. It's considered bad style to catch anything extending from Error, since it indicates "programmer error" and not "exceptional situation".
Right. But we can rename ProviderNotFoundError to ProviderNotFoundException.
Also, note that it's already feasible to handle such a scenario with a
try catch.
With this mentioned the solution wasn't too terrible for now. Just use the normal static of(context) method for retrieval and it works just fine. This could also be a method to inject a quick solution for #244
static Model of(context, {bool allowNull = false}) {
try{
return Provider.of<Model>(context, listen : false);
} catch (error){
if(!allowNull)throw error;
return null;
}
}
+1 to rename ProviderNotFoundError to ProviderNotFoundException.
Alright, as part of the 4.0.0, ProviderNotFoundError will be an Exception instead
This won't include an isNull flag though. I'm still not decided on a finite solution should be here
Closing this as ProviderNotFound is now an exception.
If you find it too verbose, you should be able to make your own utilities that reduce the boilerplate:
extension WachOrNull on BuildContext {
T watchOrNull<T>() {
try {
return watch<T>();
} on ProviderNotFoundException catch (err) {
return null;
}
}
}
Most helpful comment
There's a catch though: Soon, Dart will have non-nullable types.
A
allowNullwill not compile anymore. Maybe a secondaryofmethod that allowsnullinstead: