Mastering BuildContext in Flutter
BuildContext is something many developers don’t fully understand, but they know how to use it. However, understanding what it is can help you solve some of the nastiest bugs.
Quick Answer
BuildContext
is a way for your widget to know its own location within the Widget Tree.
In other words, it gives you context about its location. If you were blindfolded and dropped off in a random city, you would look at the context around you to figure out where you are. Maybe you would check the street signs, the position of the sun, or some landmarks to figure out where you are. BuildContext
are those signs and landmarks for each widget’s location within the Widget Tree.
BuildContext is most commonly used to look up the Widget Tree and locate specific widgets. For example when you use Theme.of(context)
or Navigator.of(context)
you are looking up the Widget Tree to find the Theme
or Navigator
that coincides with the location of the current widget where you are calling those functions from.
Side Note before the Deep Dive
We’re going to get deep into how Flutter works under the hood. For me learning about this is fun, but there is a reason why Flutter was built as a “framework” or “toolkit” or whatever you want to call it. That’s because you don’t need to know this when you’re working with it day to day. All these things are abstracted to make it easier for you to develop your application. So if the only thing you remember from this doc is that
BuildContext
gives you location within the widget tree, you are solid 👍. But if you’re a nerd like me and like understanding how stuff works, this next section will be fun!
Deep Dive
“Everything is a widget” is a lie!
If you heard the phrase in the Flutter community that “Everything is a widget”, you have been lied to! 😳 … Well, only partially. Most of the time the developer only interfaces with widgets, but there is a lot more going on behind the scenes.
You can think of a Widget
as a blueprint for what you want Flutter and eventually the code to build. These blueprints are used to create an Element Tree and a Render Tree. The Element Tree handles the lifecycle of the application, and the Render Tree is in charge of displaying the UI. In terms of the BuildContext
, we only care about the Element Tree.
Element Tree
Each Flutter Widget
has a corresponding Element
. These elements within the Element Tree have 2 very specific purposes.
- Hold the references to the parents and child widgets.
- Hold the state of the widget
We get into how the state works within the Element Tree in a separate doc, but the first part of what an Element does is literally the BuildContext
. If you dive deep into the Flutter code, you will find the definition of Element
/// An instantiation of a [Widget] at a particular location in the tree.
///
/// An [Element] represents the use of a widget to configure a specific location
/// in the tree.
abstract class Element extends DiagnosticableTree implements BuildContext
So an Element is an implementation of BuildContext
, and thus when we use BuildContext
within our application we get access to this Element in the Element Tree to find out where we are located.
Side Note
Since the Element Tree is a “tree” you can only get location information above and below the current Widget. You cannot get information to any widgets to the side of the current one.
BuildContext
provides location vertically, but not horizontally.
Fun Story
Back in the day, before Flutter 2.0 was released, there was no such thing as a ScaffoldMessenger
widget. The way you would display a snack bar within your Flutter application was by using Scaffold.of(context).showSnackbar()
which caused the following code to show an error.
Sample Code
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
color: Colors.pink,
textColor: Colors.white,
onPressed: (){
final snackBar = SnackBar(content: Text('Hello'));
Scaffold.of(context).showSnackBar(snackBar);
},
child: Text('Display SnackBar'),
),
),
);
}
}
Error
Scaffold.of() called with a context that does not contain a Scaffold.
But how does this make sense? If you look at the code there is clearly a Scaffold
and the context is used within it. You have to be careful with situations like these. Look again, and what context
is being used. It’s using the context
that belongs to the HomePage widget. The BuildContext
in this case is looking at the widgets above the HomePage
for a Scaffold
, but not within it.
Before we used to solve this by wrapping our button in a Builder
widget which gives its own context. But now since they added the ScaffoldMessenger
widget this is no longer a worry, and you just use that instead.