What is BuildContext in Flutter?

BuildContext is one of the concepts in Flutter that most developers, even seasoned ones, find hard to understand. Many developers don’t actually know what it does or what it stands for. Yet, BuildContext is an important concept that every Flutter dev should understand deeply.

In this post, we will demystify the mystery around BuildContext.

Flutter widget tree

Everything in Flutter is a widget. Whether it is a container, text, button, providers, image, etc., everything is virtually a widget, no matter if they display a UI in the app or not.

The UI or display in Flutter comprises stacks of widgets popularly called a widget tree. If you are coming from a JavaScript background or have used either Reactjs or Angular, you will understand this. In Reactjs, the UI is made up of a tree of components. Each component is responsible for a small unit of the entire UI.

In Flutter, it is not a component, rather it is a widget. A widget is responsible for a small unit in a Flutter app. As in SPAse.g., Reactjs, the widget tree has a root widget. This is the widget from which other widgets are stacked upon, meaning there will also be parent widgets and child widgets.

A widget that renders another widget is the parent widget, which renders the the child widget. The MyApp widget is usually the root widget, just like the App component is usually the root component in React.

Let’s see an example:

              MyApp
                |
            Container
                |
               Row
                |
            ----------
            |        |
          Text   FlatButton

In the above diagram, we can see a widget tree in a Flutter app. The MyApp is the root widget, and it is the parent of all the widgets in the tree. The MyApp widget renders the Container widget, and the Container widget renders the Row widget. The Row widget renders both Text and FlatButton widgets.

So, we can say that MyApp is the parent of Container, and that the Container is the parent of Row and the child of MyApp. The Row is the child of Container and parent of Text and FlatButton. Text and FlatButton are the children of Row.

Now that we can see the relationship, let’s see how BuildContext comes in.

What is BuildContext?

BuildContext is a locator that is used to track each widget in a tree and locate them and their position in the tree. The BuildContext of each widget is passed to their build method. Remember that the build method returns the widget tree a widget renders.

Each BuildContext is unique to a widget. This means that the BuildContext of a widget is not the same as the BuildContext of the widgets returned by the widget.

MyApp {
    build(BuildContext ctx) {
        return Container(
            child: Row(
                children: [
                    Text(),
                    FlatButton()
                ]
            )
        )
    }
}

The BuildContext in the MyApp widget is different from the BuildContext in the Container widget and all widgets in its tree. So, the BuildContext of the MyApp is the BuildContext parent of the BuildContexts of its child widgets.

The MyApp has its BuildContext, Container has its BuildContext, Row has its BuildContext, and Text and FlatButton have their own BuildContext, all of which are unique to each other.

Useful methods in BuildContext

findAncestorWidgetOfExactType

Returns the nearest ancestor widget of the given type T, which must be the type of a concrete Widget subclass.

This method is used to locate or find a widget of a particular type in the widget tree. This method will go up the widget tree from the widget it was called from, and try to locate the first widget in the tree whose type is the same one passed to the method.

Let’s say we have this widget tree: MyApp -> Scaffold -> Center -> Row -> Container -> Row -> Text -> TextButton. If the method is called from the Text widget:

context.findAncestorWidgetOfExactType(Row);

The method will traverse up the widget, starting from the Text widget and stopping when it locates a widget whose type is Row. So, the first Row in-between Container and Text will be returned.

findAncestorStateOfType

Returns the State object of the nearest ancestor StatefulWidget widget, an instance of the given type T.

This method is just like the findAncestorWidgetOfExactType method, b. Still, this returns the State object of a StatefulWidget widget whose instance is the same as the instance passed to the method.

Conclusion

We have seen that BuildContext is crucial in understanding how Flutter works. Understanding how Flutter works deepens our knowledge of the framework and helps us build apps confidently.