skip to content

Widget Kinds & Lifecycle

The widget building blocks of a screen: stateless and stateful widgets, State callbacks, BuildContext lookups, inherited data and keys. Interviewers use them to spot who has debugged lost state.

part ofFlutteroverview, primer and where to startread it →
on this pageshow

explore

questions

26

In Flutter, what is a BuildContext, and how does a call like Theme.of(context) use it to find a value?

level: juniorimportance: must knowfreq 74%

answer

  1. a handle to one tree position
  2. BuildContext objects are Elements
  3. each widget gets its own
  4. lookups walk toward the root
  5. a dependency that triggers rebuilds

basics

~10 s

A BuildContext is the widget's Element, its handle to one position in the tree. Theme.of(context) finds the nearest Theme above that position and registers a dependency, so the widget rebuilds when that theme changes.

solid answer

~50 s

Every widget in the tree is represented by an `Element`, and the `BuildContext` passed to `build` is that element seen through a narrower interface, which exists to discourage manipulating elements directly. Because it marks a position, lookups are relative to it and only go upward, toward the root. `Theme.of(context)` calls `dependOnInheritedWidgetOfExactType`, which returns the nearest enclosing theme data in constant time and records this element as a dependent, so it is rebuilt when that theme changes. Other lookups, such as `Scaffold.of` or `Navigator.of`, walk ancestor elements one by one and register nothing. Two consequences matter in practice: a widget's own context sits above the widgets its `build` returns, and a context is only valid while its element is mounted, so values it returns should not be cached and the context itself should not be stored for later.

code

dart · 22 lines
dart
import 'package:flutter/material.dart';

class LoanTile extends StatelessWidget {
  const LoanTile({super.key, required this.title, required this.due});

  final String title;
  final DateTime due;

  @override
  Widget build(BuildContext context) {
    // Both lookups start at this tile's element and walk upward.
    final textTheme = Theme.of(context).textTheme; // dependency: rebuilds on theme change
    final width = MediaQuery.sizeOf(context).width; // dependency on the size aspect
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: width > 600 ? 32 : 16),
      child: ListTile(
        title: Text(title),
        subtitle: Text('Due ${due.toLocal()}', style: textTheme.bodyMedium),
      ),
    );
  }
}

go deeper

for a junior

Recall that BuildContext marks the widget's place in the tree and that X.of(context) finds the nearest X above that place.

for a middle

Explain that BuildContext is the Element, the difference between O(1) inherited lookups that subscribe and O(N) ancestor walks that do not, and why lookups cannot see children.

for a senior

Apply the position model to bugs: lookups from the wrong context, cached lookup results going stale, and stored contexts used after their element is unmounted.

for a principal

Guide API design for shared services around context lookups, choosing between inherited scopes and explicit parameters so dependencies stay visible and testable.

## A handle to a position Flutter describes UI with immutable **widgets**, but what persists in the running app is a tree of **elements**, one per widget position. The framework passes a `BuildContext` to every `build` method and exposes it as `State.context`. The framework's documentation calls it 'a handle to the location of a widget in the widget tree' and states plainly that `BuildContext` objects are actually `Element` objects. The interface exists to discourage direct manipulation of elements: it exposes `widget`, `mounted`, the lookup methods and a few helpers, but not the element's mount, update and rebuild machinery. ## Each widget has its own - Every widget gets its own context, and that context is the **parent** of the widgets its `build` returns. - So a lookup from a build method's own context cannot see widgets that the same build method creates; it starts above them. - A `Builder` widget, or an extracted child widget, provides a context further down when you need one below something you just built. ## How X.of(context) finds things Most static `of` methods, such as `Theme.of`, `MediaQuery.of` or `Navigator.of`, take a context so they can answer 'what is the nearest X above this position?'. They use two families of lookup: | Lookup family | Used by | Cost | Registers a rebuild dependency | |---|---|---|---| | Inherited-widget lookup (`dependOnInheritedWidgetOfExactType`) | `Theme.of`, `MediaQuery.of` | O(1), a map read on the element | Yes | | Ancestor walk (`findAncestorStateOfType`) | `Scaffold.of`, `Navigator.of` | O(N) in the depth walked | No | The inherited lookup is cheap because each element carries a map from inherited-widget type to the nearest such element above it. When it registers a dependency and the inherited widget later changes, the framework calls `didChangeDependencies` on dependent States and rebuilds the dependents. The ancestor walk simply follows parent links until it finds a matching State. ## Rules that follow from being a position 1. **Do not cache lookup results beyond one synchronous function.** The documentation warns that a context can move with its subtree, so values obtained from it can go stale; read them again in the next `build`. 2. **Do not store a context in a field for later use.** It becomes invalid when its element is unmounted. 3. **Check `context.mounted` after an asynchronous gap** before using it again; once unmounted, a context never becomes mounted again. ## A library-loan screen example A loan list tile shows a due date styled with `Theme.of(context).textTheme.bodyMedium` and adapts padding using `MediaQuery.sizeOf(context)`. Both lookups start at the tile's element and move upward to the nearest `Theme` and `MediaQuery`, which `MaterialApp` provides. Because both register dependencies, switching to dark mode or rotating the device rebuilds the tile with new values, with no extra code. ## Common misunderstandings - The context is **not** one global app object; there is one per element. - It is **not** the widget instance; the widget is `context.widget`, and it is replaced on every parent rebuild while the element stays. - Lookups **never** search down into children. - Not every `of` method is O(1) or subscribes; that depends on which lookup it uses.

  • Why does Flutter hand you a BuildContext instead of the Element itself?
    The framework documents that the interface exists to discourage direct manipulation of `Element` objects. `BuildContext` exposes what widget code legitimately needs, such as the current `widget`, `mounted`, inherited and ancestor lookups and a few render helpers, while hiding mount, update and rebuild, which only the framework should drive.
  • Is a widget's context the same one its children receive?
    No. Each widget has its own context, and it is the parent of the widgets its `build` returns. A lookup through the builder's context therefore starts above anything that same build created, which is why a `Theme` or `Scaffold` created in a build method is invisible to lookups through that build's own context. A `Builder` or an extracted child widget gives a context below it.

saying these in an interview costs you the question

  • BuildContext is one global object shared by the whole app
  • Theme.of searches down into the widgets that build returns
  • BuildContext is simply the widget instance itself
  • Store the context in a field so it can be used anywhere later
  • Every X.of lookup is a constant-time map read
open as a page

In Flutter, what problem does an InheritedWidget solve, and how do you declare one so descendants can read its data?

level: juniorimportance: must knowfreq 62%

basics

~20 s

An InheritedWidget makes a value available to every descendant without passing it through each constructor. You subclass it with final fields, add static of/maybeOf methods that register a dependency, and override updateShouldNotify so only registered dependents rebuild when the value changes.

open as a page

In Flutter, what is a widget's key for, and when do you actually need to give a widget one?

level: juniorimportance: must knowfreq 74%

basics

~20 s

A key tells Flutter which old widget a new one replaces: an element is reused only when runtimeType and key match. Same-type stateful siblings that can be inserted, removed or reordered need one, or their state stays with the position.

open as a page

In Flutter, in what order does the framework call a State object's lifecycle methods, from createState to dispose?

level: juniorimportance: must knowfreq 80%

basics

~20 s

createState, then the State is mounted, initState runs once, didChangeDependencies follows, then build. Later builds follow setState, didUpdateWidget or a dependency change; on removal deactivate runs, and dispose ends it unless the subtree is reinserted within that frame.

open as a page

In Flutter, what is the difference between a StatelessWidget and a StatefulWidget, and when do you actually need the stateful one?

level: juniorimportance: must knowfreq 85%

basics

~20 s

A StatelessWidget builds only from its final fields and inherited data; a StatefulWidget creates a long-lived State object that holds changing values and rebuilds via setState. Choose stateful when the widget itself owns data that changes while it is on screen.

open as a page

In Flutter, what does calling setState on a State object actually do, and when does build() run afterwards?

level: juniorimportance: must knowfreq 76%

basics

~20 s

setState runs its callback synchronously, then calls markNeedsBuild on the State's element, which marks it dirty and schedules a frame. build() runs during that next frame, not inside the setState call, and several calls before the frame produce one build.

open as a page

In Flutter, how do ValueKey, ObjectKey and UniqueKey differ in what they compare, and which fits items loaded from an API?

level: middleimportance: must knowfreq 58%

basics

~10 s

ValueKey equals a key of the same runtime type whose value is ==; ObjectKey needs the very same object (identical); UniqueKey equals only itself. For API data, ValueKey(item.id) survives refetches that build new objects.

open as a page

In Flutter, why does calling Theme.of(context) or MediaQuery.of(context) inside initState fail, and where should that code go instead?

level: middleimportance: must knowfreq 66%

basics

~20 s

Theme.of and MediaQuery.of register a dependency, and initState runs only once, so a value read there would never refresh; debug builds assert it. Read the value in build, or in didChangeDependencies when derived work is expensive.

open as a page

A Flutter library-loan screen awaits a renewal call and then shows a SnackBar through ScaffoldMessenger.of(context); what can go wrong, and how do you write it safely?

level: seniorimportance: must knowfreq 62%

basics

~20 s

During the await the user may pop the screen, unmounting the element; using its context afterwards then trips assertions or acts on a dead position. Check context.mounted after the await, or capture ScaffoldMessenger.of(context) before it.

open as a page

In Flutter, what is the difference between dependOnInheritedWidgetOfExactType and getInheritedWidgetOfExactType, and when would you choose each?

level: middleimportance: should knowfreq 38%

basics

~20 s

Both return the nearest InheritedWidget of type T in O(1); dependOnInheritedWidgetOfExactType also registers the context as a dependent, so it rebuilds when that widget changes. Use it for data build displays; use getInheritedWidgetOfExactType for one-off reads where a rebuild is unwanted.

open as a page

In Flutter, why does Scaffold.of(context) throw when called from a button in the build method that creates that Scaffold, and how do you fix it?

level: middleimportance: should knowfreq 60%

basics

~20 s

The build method's context belongs to the widget that builds the Scaffold, so it sits above that Scaffold and the upward lookup never meets it. Use a Builder or an extracted child widget to get a context below the Scaffold.

open as a page

In Flutter, why does calling MediaQuery.of(context) rebuild a widget more often than expected, and how do accessors like MediaQuery.sizeOf fix it?

level: middleimportance: should knowfreq 48%

basics

~20 s

MediaQuery.of registers an unconditional dependency, so the widget rebuilds whenever any MediaQueryData field changes, such as keyboard insets. MediaQuery is an InheritedModel; sizeOf, widthOf and paddingOf register one aspect and rebuild only when that value changes.

open as a page

In Flutter, when does the framework call an InheritedWidget's updateShouldNotify, and what goes wrong when it compares the wrong thing?

level: middleimportance: should knowfreq 42%

basics

~20 s

updateShouldNotify runs only when the InheritedWidget's position receives a new widget instance; it gets the old widget and returns whether dependents must rebuild. Comparing too loosely misses changes; comparing a freshly built object by identity rebuilds every dependent every time.

open as a page

In Flutter, what does a GlobalKey give you that a ValueKey does not, and why do the docs call reparenting with one relatively expensive?

level: middleimportance: should knowfreq 50%

basics

~20 s

A GlobalKey is unique app-wide, exposes currentState, currentContext and currentWidget, and lets an element keep its State while moving to a new parent within one frame. That move deactivates and reactivates the subtree and rebuilds inherited-widget dependents.

open as a page

In Flutter, when does a State's didUpdateWidget run versus didChangeDependencies, and what work belongs in each?

level: middleimportance: should knowfreq 55%

basics

~20 s

didUpdateWidget(oldWidget) runs when the parent rebuilds with a new same-type, same-key widget; compare old and new fields and swap subscriptions there. didChangeDependencies runs after initState and whenever a depended-on inherited widget changes. Build follows both.

open as a page

In Flutter, why is extracting part of a build method into its own widget class usually better than a helper method returning Widget?

level: middleimportance: should knowfreq 52%

basics

~20 s

An extracted widget gets its own element and BuildContext, so it can own state and rebuild alone, be skipped when its instance is unchanged, and look up ancestors from its own position. A helper method's output is rebuilt with every parent build.

open as a page

In Flutter, when does the framework call createState, and how does one State object outlive the many widget instances built for it?

level: middleimportance: should knowfreq 58%

basics

~20 s

createState runs when a StatefulWidget is inflated into a new element. When the parent later rebuilds with a same-type, same-key widget at that spot, the element keeps its State, repoints State.widget at the new instance and calls build again.

open as a page

In a Flutter playlist, sorting moves each stateful TrackTile's checkbox tick to the wrong track, and adding ValueKey(track.id) to TrackTile only made ticks vanish; what is going on?

level: seniorimportance: should knowfreq 47%

basics

~20 s

Keys are only compared among one parent's direct children. The list sees keyless wrappers matched by position, so the inner TrackTile's key mismatches and its State is recreated. Key each item's outermost widget; builder lists also need findChildIndexCallback.

open as a page

A Flutter barometer widget listens to a pressure stream in initState and later logs 'setState() called after dispose()'; what went wrong, and how should it be structured?

level: seniorimportance: should knowfreq 46%

basics

~20 s

The stream subscription was never cancelled, so readings keep arriving after the State was disposed and each one calls setState. Keep the StreamSubscription, cancel it in dispose before super.dispose(), and swap it in didUpdateWidget when the stream changes.

open as a page

Why does a Flutter tip-summary StatefulWidget that copies widget.bill into a field in initState keep showing the old total after the parent passes a new bill, and how do you fix it?

level: seniorimportance: should knowfreq 40%

basics

~20 s

The State outlives each widget instance: initState ran once, so the copied field keeps the first bill while State.widget already holds the new one. Read widget.bill in build, or reconcile the copy in didUpdateWidget when a local copy is genuinely needed.

open as a page

In Flutter, what does context.findAncestorStateOfType<T>() do, what does it cost, and why do the docs discourage relying on it in build methods?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

It walks up the element chain to the nearest StatefulWidget whose State is a T and returns that State. The walk is O(depth) and registers no dependency, so use it for one-off imperative calls in handlers, not to read data in build.

open as a page

In Flutter, how does InheritedNotifier differ from a plain InheritedWidget, and when would you use it for a changing setting?

level: middleimportance: nice to knowfreq 18%

basics

~20 s

InheritedNotifier holds a Listenable and notifies its dependents whenever that Listenable fires, without anyone rebuilding the scope. Its updateShouldNotify only handles the notifier object being replaced. Use it when a shared, mutable controller should drive dependents directly.

open as a page

In Flutter, why does an ExpansionTile in a long ListView collapse after being scrolled away and back, and how does a PageStorageKey fix it?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

Off-screen items in a lazy ListView are disposed, so the tile's new State starts collapsed. With a unique PageStorageKey, ExpansionTile writes its expanded flag to the route's PageStorage bucket and reads it back when rebuilt.

open as a page

In Flutter, what is the difference between a State's deactivate and dispose callbacks, and when does activate run?

level: middleimportance: nice to knowfreq 24%

basics

~20 s

deactivate runs when a State's subtree is removed from the tree; if it is reinserted elsewhere before the frame ends, typically a GlobalKey graft, activate and build follow. Otherwise dispose runs at the frame's end and the State can never build again.

open as a page

In Flutter, why is a StatefulWidget's build method defined on its State class rather than on the widget itself?

level: middleimportance: nice to knowfreq 20%

basics

~20 s

Closures created in build capture this; on State that is the long-lived object whose widget getter always points at the newest configuration, so callbacks never read a stale widget. It also lets subclasses such as AnimatedWidget keep their State private.

open as a page

In Flutter, how do you build an InheritedModel so a widget that reads only the unit system does not rebuild when the map style changes?

level: seniorimportance: nice to knowfreq 22%

basics

~10 s

Extend InheritedModel<Aspect>, expose accessors that call InheritedModel.inheritFrom with an aspect, and override updateShouldNotify plus updateShouldNotifyDependent, which receives each dependent's aspect set and returns true only if a field for one of those aspects changed.

open as a page