Inherited Widgets In-depth

Cavin Macwan
6 min readJun 24, 2023

--

Hey Folks!👋

Have you ever wondered what happens behind the scenes when you write Theme.of(context) or MediaQuery.of(context) ?🤔 If not, then in this article, you will learn everything about InheritedWidgets along with some fun facts 😉

This blog is for both beginner and experienced developers so that everyone can benefit from it. So without further a do, let’s get started 😄

Table of Contents:

Need of an Inherited Widget

We all have heard that Everything is a widget in Flutter. While this statement is not true, we can say that Widget plays a crucial role while developing apps in Flutter.

In Flutter, there’re so many types of widgets such as StateLessWidget , StatefulWidget , RenderObjectWidget and so on. But most of the time, we mainly use StatelessWidget and StatefulWidgets. Then, where does an InheritedWidget sit?🤔

To understand the need for an InheritedWidget, let’s look at the example of this Widget Tree:

Now let’s go through it:

  • We want to access the userName property in the CustomText Widget. But to access this property, we’ve to pass the userName property inside every Widget’s constructor 🏗️
  • Here, you can see we had to pass userName from just 3 widgets to get inside CustomText. But for that, we had to write a lot of boilerplate code. Not to forget that we also created a dependency on every widget which is not a good practice.

Thus, we needed a more robust💪 solution than just passing the data in every Widget’s constructor 🏗️

As you guessed, InheritedWidget is the solution to this problem. 😉 But how does anInheritedWidget helps us to solve this problem? To answer this, let me show you the following graph📈 to understand it properly.

As you can see, you can put InheritedWidget at the top level and directly reach to that widget whenever you want to access the data. Pretty cool, isn’t it?😃

Now let’s see how you can implement this in code.

Implementation of an Inherited Widget

  • To create an InheritedWidget , you have to extend your class with InheritedWidget
  • Then you’ve to implement 1 method override: updateShouldNotify

Let’s learn this by an example:

Here, we’ve got a few new things to talk about:

  1. We’re taking the child Widget from the constructor
  2. updateShouldNotify : This method is called whenever the data inside InheritedWidget changes. If this method returns true, it means that the child widgets who are depending on this InheritedWidget will be rebuilt. In this method, we’re getting the old InheritedWidget, so that we can verify if the data inside InheritedWidget has been changed or not. Sounds too complex? Don’t worry because we’re gonna talk about it later in-depth 😉
  3. static UserDataInheritedWidget? of(BuildContext context) : Whenever you want to get the data from the InheritedWidget, you can call this method to get the data inside this InheritedWidget .

Fun Fact: Both BLoC and Provider package uses InheritedWidgets behind the scenes 😮

Now you know that you were using InheritedWidget since the beginning because whenever you write Theme.of(context) or MediaQuery.of(context) , you were actually getting the data from the respectiveInheritedWidget

Now let’s see how you can get the data from the child👶 widget.

To get the reference of the InheritedWidget , you can write this sentence in either build method in case of a StatelessWidget or in didChangeDependencies method in case of StatefulWidget like this:

StatelessWidget Example
StatefulWidget Example

Now that you know how you can use InheritedWidget , let’s take a more deep dive into the mechanism🤖 of it.

Inherited Widget In-depth

Consider this line: UserDataInheritedWidget.of(context)?.userName

  • In this line, we’re getting the reference of the UserDataInheritedWidget which is placed on the top of the Widget tree.
  • Thus, whenever you write .of(context), it registers your widget(In our case DemoWidget) as a listener👂 for the UserDataInheritedWidget
  • Therefore, whenever the value inside UserDataInheritedWidget changes, the widgets that are dependent on it get rebuilt. We will see an example of this in the end.

Some rules to follow while accessing the data from an InheritedWidget :

  • You should avoid calling .of(context) method inside the initState of a StatefulWidget because it will not rebuild your Widget when the configuration of an InheritedWidget changes ❌
  • You can call .of(context) method inside the build , didChangeDependencies or in didUpdateWidget ✅

Here’s an example of where you can call the .of(context) method:

Ok, we can call .of(context) method inside these lifecycle methods, but how does it work? 🤔

To answer this, let’s first understand which dependency we are talking about in didChangeDependencies 🤔💭

The answer is these dependencies are created by the dependOnInheritWidgetOfExactType function. This function was implemented when we were creating an InheritedWidget’s static of(BuildContext context) method.

Hence, whenever the data💽 inside an InheritedWidget changes, it will call the didChangeDependencies method.

You can also call .of(context) inside build methods as well since the performance difference won’t be that much significant, but since we’ve so many widgets in a bigger app, it’s good to use this method inside didChangeDependencies

Fun Fact: Provider calls getElementForInheritedWidgetOfExactType method when you set the listen property to false in Provider.of<AppState>(context, listen: false); so that widgets don’t get rebuild when the data inside InheritedWidget changes.

Now that you know about InheritedWidgets in-depth, let’s see how we can change the configuration of an InheritedWidget so that the widgets that are depending on it get rebuilt.

Demo:

  • First, let’s create a ColorWidget that extends the InheritedWidget:
  • Here, we are passing color along with onColorChanged method inside the constructor of this Widget.
  • In the updateShouldNotify , we’re checking if the color has been changed or not. And if it’s changed, then we’re returning true so that the widgets that are depending on this InheritedWidget gets rebuilt.

Now, let’s see the code for the StatefulWidget that inserts this InheritedWidget into the widget tree:

  • In this StatefulWidget , we are inserting the ColorWidget which is an InheritedWidget , we’re also setting the color 🎨 variable to green 🟢 color when we press on the ElevetedButton.
  • color variable of the state object is passed inside the InheritedWidget

Now, let’s see the code for ColorCardWidget which is inside the Column:

Here, you can see that in this StatelessWidget, we are getting the color🎨 from the InheritedWidget . Therefore, whenever the value of color changes, The ColorCardWidget will get rebuilt.

Now, if you run the code, you should see an output like this:

Therefore, we can confirm that by writing .of(context) method, it will register that widget as a listener to that InheritedWidget so that it can rebuild itself whenever the data inside the InheritedWidget changes.

If you want to try these examples on your own then you can check out my GitHub repository:

I hope I was able to give you some insights on Inherited Widgets by this article. If you didn’t understand any of this part or have any doubts, then you can ask me in the comments, or on my LinkedIn and Twitter.

Keep clapping 👏 (you can appreciate it by clapping 50 times)

We are building a community for developers where anyone can share their ideas or content, ask doubts about Flutter/other tech, collaborate with each other and become a better developer. So if you are interested in being part of this community then you can join our discord server by this link: https://7span.in/club

References:

--

--

Cavin Macwan

Passionate mobile developer. One thing I like more than learning new things: sharing them #FlutterDev| Developer @7Span | Contributor