StatefulComponent class abstract

A component that has mutable state.

State is information that (1) can be read synchronously when the component is built and (2) might change during the lifetime of the component. It is the responsibility of the component implementer to ensure that the State is promptly notified when such state changes, using State.setState.

A stateful component is a component that describes part of the user interface by building a constellation of other components that describe the user interface more concretely. The building process continues recursively until the description of the user interface is fully concrete (e.g., consists entirely of DOMComponents, which describe concrete DOM elements).

Stateful components are useful when the part of the user interface you are describing can change dynamically, e.g. due to having an internal clock-driven state, or depending on some system state. For compositions that depend only on the configuration information in the object itself and the BuildContext in which the component is inflated, consider using StatelessComponent.

StatefulComponent instances themselves are immutable and store their mutable state either in separate State objects that are created by the createState method, or in objects to which that State subscribes, for example Stream or ChangeNotifier objects, to which references are stored in final fields on the StatefulComponent itself.

The framework calls createState whenever it inflates a StatefulComponent, which means that multiple State objects might be associated with the same StatefulComponent if that component has been inserted into the tree in multiple places. Similarly, if a StatefulComponent is removed from the tree and later inserted in to the tree again, the framework will call createState again to create a fresh State object, simplifying the lifecycle of State objects.

A StatefulComponent keeps the same State object when moving from one location in the tree to another if its creator used a GlobalKey for its key. Because a component with a GlobalKey can be used in at most one location in the tree, a component that uses a GlobalKey has at most one associated element. The framework takes advantage of this property when moving a component with a global key from one location in the tree to another by grafting the (unique) subtree associated with that component from the old location to the new location (instead of recreating the subtree at the new location). The State objects associated with StatefulComponent are grafted along with the rest of the subtree, which means the State object is reused (instead of being recreated) in the new location. However, in order to be eligible for grafting, the component must be inserted into the new location in the same build phase in which it was removed from the old location.

Performance considerations

There are two primary categories of StatefulComponents.

The first is one which allocates resources in State.initState and disposes of them in State.dispose, but which does not depend on InheritedComponents or call State.setState. Such components are commonly used at the root of an application or page, and communicate with subcomponents via ChangeNotifiers, Streams, or other such objects. Stateful components following such a pattern are relatively cheap (in terms of CPU and GPU cycles), because they are built once then never update. They can, therefore, have somewhat complicated and deep build methods.

The second category is components that use State.setState or depend on InheritedComponents. These will typically rebuild many times during the application's lifetime, and it is therefore important to minimize the impact of rebuilding such a component. (They may also use State.initState or State.didChangeDependencies and allocate resources, but the important part is that they rebuild.)

There are several techniques one can use to minimize the impact of rebuilding a stateful component:

  • Push the state to the leaves. For example, if your page has a ticking clock, rather than putting the state at the top of the page and rebuilding the entire page each time the clock ticks, create a dedicated clock component that only updates itself.

  • Minimize the number of nodes transitively created by the build method and any components it creates. Ideally, a stateful component would only create a single component, and that component would be a RenderObjectComponent. (Obviously this isn't always practical, but the closer a component gets to this ideal, the more efficient it will be.)

  • If a subtree does not change, cache the component that represents that subtree and re-use it each time it can be used. It is massively more efficient for a component to be re-used than for a new (but identically-configured) component to be created. Factoring out the stateful part into a component that takes a child argument is a common way of doing this. Another caching strategy consists of assigning a component to a final state variable which can be used in the build method.

  • Use const components where possible. (This is equivalent to caching a component and re-using it.)

  • When trying to create a reusable piece of UI, prefer using a component rather than a helper method. For example, if there was a function used to build a component, a State.setState call would require Flutter to entirely rebuild the returned wrapping component. If a Component was used instead, Flutter would be able to efficiently re-render only those parts that really need to be updated. Even better, if the created component is const, Flutter would short-circuit most of the rebuild work.

  • Avoid changing the depth of any created subtrees or changing the type of any components in the subtree. For example, rather than returning either the child or the child wrapped in an IgnorePointer, always wrap the child component in an IgnorePointer and control the IgnorePointer.ignoring property. This is because changing the depth of the subtree requires rebuilding, laying out, and painting the entire subtree, whereas just changing the property will require the least possible change to the render tree (in the case of IgnorePointer, for example, no layout or repaint is necessary at all).

  • If the depth must be changed for some reason, consider wrapping the common parts of the subtrees in components that have a GlobalKey that remains consistent for the life of the stateful component. (The KeyedSubtree component may be useful for this purpose if no other component can conveniently be assigned the key.)

By convention, component constructors only use named arguments. Also by convention, the first argument is key, and the last argument is child, children, or the equivalent.

See also:

Inheritance
Implementers

Constructors

StatefulComponent({Key? key})
Initializes key for subclasses.
const

Properties

hashCode int
The hash code for this object.
no setterinherited
key Key?
Controls how one component replaces another component in the tree.
finalinherited
runtimeType Type
A representation of the runtime type of the object.
no setterinherited

Methods

createElement() Element
Creates a StatefulElement to manage this component's location in the tree.
override
createState() State<StatefulComponent>
Creates the mutable state for this component at a given location in the tree.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited