Flutter: Element and RenderObject

Tram Ho

“Everything is Widgets”. This is a saying that you often come across when learning about Flutter.

Team Flutter said “A widget is an immutable description of part of a user interface”. When you read Flutter’s source code, you should see the following definition of the Widget class:

The ” immutable ” annotation shows us that all properties in the Widget must be final. Therefore the properties in each Widget instance cannot be changed. In reality, however, the UI is not “immutable”, it is mutable. So how does Flutter manage the UI state in response to changes?

Flutter has 3 “trees”: Widget tree, Element tree, RenderObject Tree. They have different concepts, but together they optimize the UI rendering performance as much as possible. Widgets are no stranger to you, so what are Element and RenderObject?

I. Element

“An instantiation of a Widget at a particular location in the tree” – “Describe a Widget at a specific location on a ‘tree'”

Unlike Widgets, Elements are “mutable”. This means that its properties can be changed without creating a new element. It handles updating and changing UI. Or you can think of it as it manages the lifecycle of Widgets. Each elment holds a reference to Widget and RenderObject

II. RenderObject

The main component is responsible for drawing on your UI

RenderObject: handle size, layout, and painting

When Flutter draws your UI, it doesn’t rely on the Widget tree, but on the RenderObject tree, which controls all the sizes, layouts, and logic for drawing the actual 1widget. Hence RenderOject is very expensive to initialize.

III. Specific example

To better visualize the above 3 trees, we see the following simple example:

During render time, Flutter calls for the widget’s build () function to produce several new widgets, in case they are nested:

Some boxes are grayed out for widgets that were not added by you. Along with the Widget tree, Flutter also constructs the Element tree and the Render tree parallel. They are created by createElement () and createRenderObject (), respectively, when the widgets are iterated. Note: createElement is always called on widgets, but createRenderObject is only called on elements of type RenderObjectElement .

We’ll go into analyzing the trees to see how Flutter actually works.

  • Render tree : As shown above, RenderObject contains all the logic for rendering the corresponding widget, and it is very expensive to create. It manages layout, constraints, hit testing and painting. The framework keeps them in memory for as long as possible, changing the properties value whenever the opportunity arises. There are many types of renderings such as:
    • RenderFlex
    • RenderParagraph
    • RenderBox …

During build, the framework only updates or creates a new RenderObject when it encounters a RenderObjectElement in the element tree.

  • Element tree : An element linking between Widget and its corresponding RenderObject so it holds internal references. The elemetns are optimized for comparing items and looking for changes, but they do not render. There are 2 types of elements:

+ ComponentElement: An element contains other elements. It is associated with a widget that contains another widget:

+ RenderObjectElement .: An element involved in the stages of painting, layout, hit testing.

Essentially an element tree is a series of ComponentElement and RenderObjectElement depending on the widget they refer to. As in the above example, the Container will create a ComponentElement because it contains another widget inside.

  • Widget tree: It is made up of classes that extend StatelessWidget or StatefulWidget. They are used to build UI and are inexpensive to create (much less than RenderObject).

Whenever the widget tree changes (eg by a state management library), Flutter will use the element tree to compare the new widget tree and the render tree. Element is the “middleware” between Widget and RenderObject that is used to quickly compare and keep trees up to date.

  1. A Widget is considered “lightweight” and it can be initialized quickly, so regular rebuilds shouldn’t be a problem. All widgets are immutable and that is why the state of StatefulWidget is implemented in a separate class. A StatefulWidget itself is immutable but its state is mutable

  1. RenderObject is relatively “expensive” and takes time to initialize so it is only re-created when absolutely necessary. Most of the times they just update the value of properties.

At each rebuild, Flutter goes through the entire tree looking for changes to the widgets. If a widget’s type changes, it will be deleted and replaced by the new widget (with the element and the renderObject associated with it). All 3 subtree will be recreate. If the widget has the same type and only a few properties change, the element will not be affected, renderObject will be updated, for example:

Change the text to:

When rebuilding, relying on the element tree, Flutter knows that the type stays the same (SomeText) but the propety (text) changes. So renderObject just needs to update (cheap).

Everything happens very quickly because RenderObject doesn’t need recreated but modified. However, if we change SomeText to Flutter’s Text widget:

While traversing the entire tree, the framework once again noticed the change thanks to the element tree. In particular, this time the widget type is completely different, so we need to rebuild all the subtree (widgets, elements, render). ).

In this case renderObject must be recreated because the widget has a different type so the old instance cannot be reused.

Note: The BuildContext parameter you see in any build () method basically represents the Element associated with the widget. In reality, BuildContext objects are Element objects. Team Flutter created BuildContext to avoid direct interaction with Element, Element will be used by the framework, not by us.

IV. summary

  • The Render tree is the tree that actually draws the UI elements.
  • Widget tree is built by ourselves (developer).
  • The Element tree is maintained by the framework to decide if it is time to update or re-create the RenderObject.

Refer:

flutter.dev

Giorgia’s Flutter Complete Reference Ebook

Share the news now

Source : Viblo