While we generally use Provider or GetIt to pass things around in Flutter, there are times when you don’t want to have any dependencies on these libraries, and instead just want to define your own MyFoo.of(context)
lookup. Often this is when you’re creating packages yourself.
There are quite a few deep dives tutorials into this around, but in this post we wanted to keep it extremely short and sweet.
First of all, there are 2 main types of InheritedWidgets you might create, Stateless
(some data) or Stateful
(some controller). Both are very easy, lets look at Stateless first!
Create a Stateless InheritedWidget
Lets say you have a widget, and you want to allow someone above you in the tree to pass you some simple data. Like maybe your widget relies on a special String
that you want to inherit.
Step1) Create an inherited widget that takes the Data you want to inherit:
class MyPathProvider extends InheritedWidget { MyPathProvider ({Key? key, required Widget child, required this.path}) : super(key: key, child: child); final String path; Widget build(BuildContext context) => child; }
Step2) Add .of() and updateShouldNotify() methods to your widget:
static MyPathProvider ? of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<MyPathProvider>(); @override // rebuild children if .path value changes bool updateShouldNotify(covariant MyPathProvider oldWidget) => oldWidget.path != path;
Step3) Use the widget in your tree:
return MyPathProvider(path: "some/path", child: ...)
You’re done! You can now try and look this up using MyPathProvider.of(context).user
from any descendants of MyPathProvider
.
Create a Stateful InheritedWidget
Step 1) Create a StatefulWidget
that takes a child, and declares it’s state as public.
class MyFoo extends StatefulWidget { const MyFoo({Key? key, required this.child}) : super(key: key); final Widget child; @override MyFooState createState() => MyFooState(); } class MyFooState extends State<MyFoo> { @override Widget build(BuildContext context) => widget.child; }
Step 2) Create a matching InheritedWidget
, with a field for your state.
class _MyInheritedFoo extends InheritedWidget { _MyInheritedFoo({Key? key, required Widget child, required this.state}) : super(key: key, child: child); final MyFooState state; @override // Always rebuild children if state changes bool updateShouldNotify(covariant InheritedWidget oldWidget) => true; }
Step 3) Inside your state’s build
method, wrap the .child in the InheritedWidget
, and pass the state as an argument:
Widget build(BuildContext context) { return _MyInheritedFoo(child: widget.child, state: this); }
Step 4) Add a single method to your StatefulWidget
:
static MyFooState of(BuildContext context) => (context.dependOnInheritedWidgetOfExactType<_MyInheritedFoo>() as _MyInheritedFoo).state;
Step5) Use the widget in your tree return MyFoo(child: …)
You’re done! You can now look up this state from anywhere in the tree, with a simple: MyFooState state = MyFoo.of(context);
You can view the full working example on github. Happy coding 🙂
Need help building something cool in Flutter? We’d love to chat.
Should
final User user;
be
final String path;
?
Interesting topic. Thank you for posting this.
I am a rookie in Flutter, Your blogs are helping me a lot, thanks Shawn. Keep posting.
Wonderful