Immutable Flutter Widgets and React Elements are Rendering Mutable UI

Faisal Rony
4 min readMay 22, 2021

Flutter uses Widget & React uses Element to render DOM UI.

But Flutter Widget and React Elements both are immutable . Its too expensive to regenerate the full DOM on a single change .

So how it used to render muted DOM?

Flutter introduce widgets like below

Flutter widgets are built using a modern framework that takes inspiration from React. The central idea is that you build your UI out of widgets. Widgets describe what their view should look like given their current configuration and state. When a widget’s state changes, the widget rebuilds its description, which the framework diffs against the previous description in order to determine the minimal changes needed in the underlying render tree to transition from one state to the next.

React introduce elements like below

A virtual DOM element representing an instance of a DOM element, React component, or fragment.An element describes what you want to see on the screen.

So its clear that both describes the configuration of what user want to see on the screen rather than generating the UI itself. They decouple the user interface from its underlying state . With React-style APIs, it only create the UI description, and the framework takes care of using that one configuration to both create and/or update the user interface as appropriate.

Lets have some code example

React uses ReactDOM.render API call to render the DOM.

ReactDOM.render(element, container)

render() function renders a React element into the DOM in the supplied container and return a reference to the component (or returns null for stateless components) . if we change the element then

ReactDOM.render(new_element, container)

at this point render() function returns a new React elements tree as it immutable and compare with the old element tree . As the React element was previously rendered into container, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element by using virtual DOM (a representation of a UI kept in memory and synced with the “real” DOM on change) .

This process is called reconciliation.React Fiber is the new reconciliation engine in React 16.

Virtual DOM updates only the change portion

Flutter uses runAPP() to render the DOM,

void main() {
runApp(
Container(
color: Colors.blue,
child: Row(
children: [
Image.network('https://www.example.com/1.png'),
Text('A'),
],
),
);
);
}

Here it uses 3 trees to render UI

  1. Widget Tree
  2. Element Tree
  3. RenderObject

So there are actually three steps that will happen when the app starts:

  1. The runApp() function takes the given Widget and makes it the root of the widget tree.
  2. For each Widget in the tree, Flutter will create an Element by calling the createElement() method on the widget. That is how the Element tree is created.Elements are mutable.
  3. For each Element in the tree, Flutter will create a Render Object by calling createRenderObject() on a widget, creating a Render Object tree.

So now if we change the code to render some different value . As i said its decouple the user interface from its underlying state so it will not rebuild the full tree only updates the corresponding element lets have a look

Change Text('A'), to  Text('B')

As the widgets are immutable by the above change it creates a new Text element and remove the old one from the widget tree. but every widget in the widget tree has its own corresponding element on element tree . So what about that does it regenerate the corresponding element node . No it first call the function canUpdate to check what to do .

Update the element tree

The above function check 2 conditions

  1. if the widgets have the same type, even if their children are completely different
  2. If the widgets have same key or no key (their key is null)

In our case both conditions are true oldWidget and newWidget both are TextWidget & both keys are null (as no key assign).

So this function sends a message to update the element on the element tree . then the element calls the updateRenderObject function for update it self.

An element that uses a given widget as its configuration can be updated to use another widget as its configuration if, and only if, the two widgets have [runtimeType] and [key] properties that are [operator==].

Notice here we swap one immutable object with another immutable and haven't create or destroy anything else just simple update.

if you want to have a close look you can use DartDevTool . The Text element have the same renderObject Id before and after the change on the text from Hellow to Hellow faisal.

if you like the article please : 👏

Thanks for reading .

--

--