Flutter: Creating your own Inherited Widgets

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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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;
}
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; }
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
static MyPathProvider ? of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<MyPathProvider>();
@override
// rebuild children if .path value changes
bool updateShouldNotify(covariant MyPathProvider oldWidget) => oldWidget.path != path;
static MyPathProvider ? of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<MyPathProvider>(); @override // rebuild children if .path value changes bool updateShouldNotify(covariant MyPathProvider oldWidget) => oldWidget.path != path;
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
return MyPathProvider(path: "some/path", child: ...)
return MyPathProvider(path: "some/path", child: ...)
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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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;
}
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; }
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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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;
}
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; }
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Widget build(BuildContext context) {
return _MyInheritedFoo(child: widget.child, state: this);
}
Widget build(BuildContext context) { return _MyInheritedFoo(child: widget.child, state: this); }
Widget build(BuildContext context) {
    return _MyInheritedFoo(child: widget.child, state: this);
  }

Step 4) Add a single method to your StatefulWidget:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
static MyFooState of(BuildContext context) =>
(context.dependOnInheritedWidgetOfExactType<_MyInheritedFoo>() as _MyInheritedFoo).state;
static MyFooState of(BuildContext context) => (context.dependOnInheritedWidgetOfExactType<_MyInheritedFoo>() as _MyInheritedFoo).state;
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.

shawn.blais

Shawn has worked as programmer and product designer for over 20 years, shipping several games on Steam and Playstation and dozens of apps on mobile. He has extensive programming experience with Dart, C#, ActionScript, SQL, PHP and Javascript and a deep proficiency with motion graphics and UX design. Shawn is currently the Technical Director for gskinner.

@tree_fortress

4 Comments

  1. Should

    final User user;

    be

    final String path;

    ?

  2. Interesting topic. Thank you for posting this.

  3. I am a rookie in Flutter, Your blogs are helping me a lot, thanks Shawn. Keep posting.

Leave a Reply

Your email address will not be published. Required fields are marked *