skip to content

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%

answer

  1. one State per element, not per widget
  2. StatefulElement constructor calls createState
  3. same type and key keeps the element
  4. State.widget swapped on update
  5. five situations that run build

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.

solid answer

~40 s

`createState` is called from the `StatefulElement` constructor, so it runs once per element: when the widget is first inserted, once per location if the same widget appears in several places, and again if it is removed and later reinserted. When the parent rebuilds, it creates new widget instances; if the new one has the same `runtimeType` and `key` as the old one at that position, the framework updates the existing element instead of replacing it. For a stateful element that means setting `State.widget` to the new instance, calling `didUpdateWidget(oldWidget)`, and running `build`. So the `State` and its fields outlive every widget instance that configures it. `build` also runs after `initState`, after `setState`, when an inherited dependency changes, and after the State is moved to a new location.

go deeper

for a junior

Recall that createState runs once when the widget is first inserted, not on every rebuild, and that State fields survive the parent's rebuilds.

for a middle

Explain the element as the owner of the State, how an update swaps State.widget and calls didUpdateWidget, and list what triggers State.build.

for a senior

Use this model to explain real bugs: state lost when a subtree changes type, state kept when it should reset, and fields updated without setState appearing late.

for a principal

Weigh where long-lived state should be anchored in the tree so that navigation and conditional UI do not silently discard or leak it across a large app.

## Widgets are throwaway; elements persist A Flutter **widget** is an immutable configuration object. Every time a parent's `build` runs, it constructs new widget instances, so a given `StatefulWidget` subclass may be instantiated hundreds of times while a screen is open. The **element** is the long-lived object that represents one position in the tree, and for a stateful widget the element owns the **State**. The State's lifetime therefore follows the element, not any single widget instance. ## When createState runs In the framework source, `StatefulElement`'s constructor is `StatefulElement(StatefulWidget widget) : _state = widget.createState(), ...`. So `createState` runs exactly when a new element is created for the widget: 1. The first time the widget is inserted into the tree. 2. Once **per location**: the same widget class placed twice in one `build` gets two elements and two independent State objects. 3. Again after the widget is **removed and later reinserted**; the framework documents this as giving a fresh State and so a simpler lifecycle. The exception is a subtree with a `GlobalKey` grafted to a new position within the same frame, which keeps its State. It does not run when the parent merely rebuilds. ## How the State is kept across a parent rebuild When the parent's `build` returns a new widget for a slot, the framework decides what to do with the existing element: | New widget at that slot | Result for the stateful child | |---|---| | The identical instance (for example a `const` one) | Element untouched, child's `build` not called | | Same `runtimeType` and same `key` | Element updated: `State.widget` points at the new instance, `didUpdateWidget(oldWidget)` runs, then `build` | | Different `runtimeType` or `key` | Old element and State discarded, new element created, `createState` runs again | The middle row is the everyday case. In `StatefulElement.update` the framework stores the old widget, assigns the new one to the State, calls `didUpdateWidget`, and forces a rebuild. The State's fields are never touched, which is how a tip slider keeps its position while the screen above it rebuilds with, say, a new bill amount. The matching rule itself and the use of keys to control it belong to the keys topic. ## What makes State.build run The `State.build` documentation lists the situations in which the framework calls it: - after `initState` (the first build); - after `didUpdateWidget`, when the parent supplied a new configuration; - after a call to `setState`; - after an inherited widget that the previous build depended on changes; - after `deactivate`, when the State is reinserted at another location. Hot reload also rebuilds the tree, which belongs to the dev-loop topic. ## What does not make it run - Assigning to a State field without `setState`: the value changes but the element is not dirty, so nothing is rebuilt until some other trigger arrives, at which point the value appears as a surprise. - A child calling `setState`: only the child's element becomes dirty; the parent's `build` does not run. - Mutating an object that a widget holds, when nobody listens to it and nobody calls `setState`. ## Practical consequences - Read configuration through `widget.x` inside `build` or callbacks; it always refers to the newest instance. - Do not assume `initState` sees every configuration; it runs once per State. - Expect fresh State, with fields back at their initializers, whenever the widget moves to a slot where the type or key differs, or leaves the tree and returns.

  • Does a child's setState rebuild its parent?
    No. `markNeedsBuild` marks only the child's element dirty; in the next frame the child's `build` runs and the widgets it returns update the elements below it. The parent's `build` runs only if the parent was itself marked dirty or its own parent rebuilt it. Keeping slider state in a small child therefore keeps the parent's build out of each change.
  • When is the State recreated even though the widget class did not change?
    Whenever the element is discarded: the widget leaves the tree and later comes back (outside a same-frame `GlobalKey` graft), its key changes, or a widget of a different type occupies that slot in between. Each case creates a new element, whose constructor calls `createState`, so every field returns to its initializer.

saying these in an interview costs you the question

  • createState is called every time the parent rebuilds
  • The State keeps a fixed reference to the widget that created it
  • Assigning a State field without setState updates the screen at once
  • A child's setState forces its parent's build to run
  • One widget class used twice shares a single State object