
InheritedWidget provides a way to share data across the widget tree in Flutter. It serves as a container for data that can be accessed by any descendant widget in the hierarchy. Whenever the data within the InheritedWidget changes, it triggers a rebuild of all the dependent widgets in the subtree.
However, besides InheritedWidget, there are two other subclasses, InheritedNotifier and InheritedModel, that offers unique approaches to sharing data in Flutter.
In this article, we will explore each of the subclasses and how they can be implemented by code.
Positive thinking leads to positive outcomes. Try out Justly, build good habits, and start thinking positively today!
What is InheritedNotifier?InheritedNotifier is a subclass of InheritedWidget that combines the capabilities of InheritedWidget and ChangeNotifier. It propagates changes from a ChangeNotifier to descendant widgets. By wrapping ChangeNotifier with InheritedNotifier, you can automatically rebuild dependent widgets whenever the ChangeNotifier triggers updates using notifyListeners().
When creating an InheritedNotifier, you need to provide a Listenable object as its notifier parameter, such as ValueNotifier for simple objects or ChangeNotifier for complex objects.
To better understand the concept, let’s implement the demo.
We'll implement this Ui for better understanding of InheritedWidget.

Create a class that is listenable to update the state.
class User {
String? name;
String? age;
User({this.name = '', this.age = ''});
}
class UserState with ChangeNotifier {
User _user = User();
User get user => _user;
void setProfile(User updatedProfile) {
_user = updatedProfile;
notifyListeners();
}
}Nothing fancy right??
By extending ChangeNotifier, the UserState class becomes a listenable class that can be used with InheritedNotifier to propagate state changes to its dependants in the widget tree.
So, let’s go ahead and use this class in InheritedNotifier class.
class UserStateNotifier extends InheritedNotifier<UserState> {
const UserStateNotifier(
{super.key, required UserState userState, required super.child})
: super(notifier: userState);
static User of(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<UserStateNotifier>()!
.notifier!
.user;
}
@override
bool updateShouldNotify(covariant InheritedNotifier<UserState> oldWidget) {
return notifier!.user != oldWidget.notifier!.user;
}
}of method is a static method in the UserStateNotifier class that allows us to retrieve the current user profile (User) from the nearest UserStateNotifier ancestor in the widget tree.updateShouldNotify method in the UserStateNotifier class is responsible for determining whether the dependents of the InheritedNotifier widget should be rebuilt or not. By implementing this method, we can optimize the rebuilding process by rebuilding only when necessary, reducing unnecessary rebuilds, and improving performance.Let’s use it in the widget tree.
We have a simple screen that displays the user’s name and age.
To update the user state, simply tap on the FAB button, which will open a modal bottom sheet with two Textfields, where user can update their information by adding text.
class HomePage extends StatelessWidget {
HomePage({super.key});
final TextEditingController _nameController = TextEditingController();
final TextEditingController _ageController = TextEditingController();
final UserState userState = UserState();
@override
Widget build(BuildContext context) {
return Scaffold(
...
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (_) {
return Column(
children: [
TextField(
controller: _nameController,
decoration: const InputDecoration(
hintText: 'What is your name?',
border: OutlineInputBorder()),
),
const SizedBox(height: 20,),
TextField(
controller: _ageController,
decoration: const InputDecoration(
hintText: 'What is your age?',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.number,
),
ElevatedButton(
onPressed: () {
User user = User(
name: _nameController.text,
age: _ageController.text
);
userState.setProfile(user);
Navigator.pop(context);
},
child: const Text("Save"))
],
);
});
},
label: const Text('Set Profile')),
);
}
}And you’re all set to go. Great job!! 👍
class HomePage extends StatelessWidget {
....
final UserState userState = UserState();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('InheritedNotifier Demo'),
),
body: Center(
child: UserStateNotifier(
userState: userState,
child: Builder(builder: (context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Name : ${UserStateNotifier.of(context).name}',
style: const TextStyle(fontSize: 20),
),
Text(
'Age : ${UserStateNotifier.of(context).age}',
style: const TextStyle(fontSize: 20),
)
],
);
}),
),
),
floatingActionButton: FloatingActionButton.extended(
....
}
}No explanation is needed!!
We can access the user information by calling UserStateNotifier.of(context), which returns the user information from the UserState class.
When you run the app, any change made through the modal bottom sheet will be reflected in real-time without the need for explicit state management calls.
InheritedNotifier combines the functionalities of data sharing through InheritedWidget and state management through ChangeNotifier.InheritedNotifier is designed to work with a single ChangeNotifier object.InheritedNotifier works well for small to medium-sized applications where you need a simple and efficient way to share and update states across multiple widgets.InheritedWidget, InheritedNotifier provides global access to the shared state, which can make encapsulation and control challenging.InheritedModel is another subclass of InheritedWidget that provides a more granular way of sharing data. With this, you can define multiple models within a single InheritedModel widget and select specific models for each descendant widget to depend on.
Let’s understand it by implementing it in the above example.
Let’s define theInheritedModel class that we will name UserModel.
class UserModel extends InheritedModel<User> {
final User? user;
const UserModel({super.key, required super.child, this.user});
static User? of(BuildContext context) {
return InheritedModel.inheritFrom<UserModel>(context)!.user;
}
@override
bool updateShouldNotify(UserModel oldWidget) {
return user != oldWidget.user;
}
@override
bool updateShouldNotifyDependent(
UserModel oldWidget, Set<User> dependencies) {
return user != oldWidget.user && dependencies.contains(user);
}
}InheritedModel has the static of and updateShouldNotify same as InheritedNotifier. The static of method takes BuildContext and uses the inheritFrom method provided by InheritedModel to retrieve the UserModel and access its user variable.updateShouldNotifyDependent method is used to determine whether specific dependent widgets should be notified and rebuilt when the InheritedModel is rebuilt.oldWidget which represents the previous instance of the model, and dependencies, which is a set of aspects that the widget depend on. Here, we can read the aspect value of the dependent widgets and can specify the condition on which we want our dependent widgets to be rebuilt.Let’s use the InheritedModel in the UI.
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final TextEditingController _nameController = TextEditingController();
final TextEditingController _ageController = TextEditingController();
User user = User();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('InheritedNotifier Demo'),
),
body: Center(
child: UserModel(
user: user,
child: Builder(builder: (context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Name : ${UserModel.of(context)!.name}',
style: const TextStyle(fontSize: 20),
),
Text(
'Age : ${UserModel.of(context)!.age}',
style: const TextStyle(fontSize: 20),
)
],
);
}),
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (_) {
return Column(
children: [
TextField(
controller: _nameController,
decoration: const InputDecoration(
hintText: 'What is your name?',
border: OutlineInputBorder()),
),
const SizedBox(
height: 20,
),
TextField(
controller: _ageController,
decoration: const InputDecoration(
hintText: 'What is your age?',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.number,
),
ElevatedButton(
onPressed: () {
User updatedUSer = User(
name: _nameController.text,
age: _ageController.text);
Navigator.pop(context);
setState(() {
user = updatedUSer;
});
},
child: const Text("Save"))
],
);
});
},
label: const Text('Set Profile')),
);
}Pretty similar, isn’t it?
And just like that, your app is ready. Hit that Run button and update your information to see the result.
How does it work?
When you click on the button, the value of the user variable changes. As this change happens, our UserModel observes the change and its updateShouldNotify method is called. This method checks if the dependent widgets need to be rebuilt. If this method returns true, which it would if any one of the properties changes, then updateShouldNotifyDependent is called.
InheritedModel reduces the number of widget rebuilds that occur when changes are made to shared data. This optimization improves performance by only updating the widget that depends on specific changes.InheriteModel allows you to manage multiple models and control specific aspects that each dependent widget relies on.InheritedWidget, using InheritedModel requires more explicit specifications of dependencies and aspects, which can increase the complexity of the code.This is the most basic example I could come up with. In this article, we have explored InheritedNotifier and InheritedModel as subclasses of InheritedWidget in Flutter.
We’re Grateful to have you with us on this journey!
Suggestions and feedback are more than welcome!
Please reach us at Canopas Twitter handle @canopas_eng with your content or feedback. Your input enriches our content and fuels our motivation to create more valuable and informative articles for you.
Thanks for reading!! 👋 👋



Whether you need...