rrousselGit / Boundary
Programming Languages
Warning, experimental project
Boundary
Boundary is a set of widgets that takes over FlutterError.onError
and
ErrorWidget.builder
to make them composable and scoped.
If you found difficult to implement an "Oops"/Loading" screen or want explicit error reporting for only a specific subtree, then this library is for you.
Principle
Fallback UI are represented through one universal widget:
Boundary
This widget, when inserted inside the widget tree, is able to catch exceptions from descendants (and only descendants) to then create a fallback UI.
Here's a typical example:
Scaffold(
appBar: AppBar(title: const Text('hello')),
body: Boundary(
fallbackBuilder: (context, error) {
return const Center(child: Text('Oops'));
},
child: Container(
color: Colors.red,
padding: const EdgeInsets.all(50),
child: Builder(builder: (_) {
// a descendant somethow wants to abort the build
return Defer(42);
}),
),
),
);
Which renders the following:
Notice how, even if there's a Container
with padding and a red background
as child of Boundary
, the "Oops" screen doesn't show any of these:
The widget returned by fallbackBuilder
is in an entirely different widget tree.
But the failing subtree (Container -> Builder) is not removed for the tree either! Its state is preserved and it is simply offstaged, until it rebuilds successfuly.
This is proved by the following example,
which shows how Boundary
can be used to show a loading/error screen from a
FutureBuilder
deeper in the widget tree – without having a reference on
the Future
.
Boundary(
fallbackBuilder: (_, error) {
// doesn't have the reference on the Future, but
// is still able to display loading/error state
if (error is Loading) {
return const Center(child: CircularProgressIndicator());
} else if (error is NotFoundError) {
return const NotFoundScreen();
} else {
return const OopsScreen();
}
},
child: SubtreeThatHasAFutureBuilder(),
)
FAQ
How to remove the fallback screen
Once an exception is thrown, the fallback screen is shown. But you may want to stop showing that fallback at some point.
To achieve this, simply rebuild the failling widget such that it doesn't throw anymore. This will automatically remove the fallback screen.
fallbackBuilder
?
What happens if there's an exception inside If there's an exception inside fallbackBuilder
, then the exception is propagated
to the next Boundary
, until there are none anymore.
Boundary(
fallbackBuilder: (_, err) => Text(err.toString()),
child: Boundary(
fallbackBuilder: (_, err) {
print(err);
return Defer(err);
},
child: Builder(builder: (_) {
return Defer(42);
})
)
)
Using the previous snippet, this will first print 42
in the console, then
render a Text
with "42" on screen.