StatefulWidget addresses interactive scenarios that require dynamic visual changes

The StatelessWidget handles static, stateless view presentation

So, is the StatelessWidget necessary? Is StatefulWidget the panacea of Flutter?

UI Programming Paradigm

In Flutter, how to adjust the presentation style of a control (Widget), the UI programming paradigm.

In native systems (Android, iOS) or native JavaScript development, view development is imperative, telling the operating system or browser exactly how to do things. For example, if you want to change a copy of the interface, you need to find the specific text control and call its control method commands to complete the text change.

The following code shows how to change the presentation copy of a text control to Hello World in Android, iOS, and native Javascript:

Hello World TextView TextView = (TextView) findViewById(R.i.D.txt); textView.setText("Hello World"); Hello World UILabel *label = (UILabel *)[self.view viewWithTag:1234]; label.text = @"Hello World"; // Native JavaScript sets a text control display copy to Hello World Document.querySelector ("#demo").innerHTML = "Hello World!";
Copy the code

In contrast, the view development of Flutter is declarative and its core design idea is to separate view and data, which is exactly the same as React.

Achieving the same requirements with Flutter is tricky: in addition to designing the layout of the Widget, a copywriting data set needs to be maintained in advance and the Widget needs to be bound to that data set for the Widget to render against.

However, when you need to change the copywriting of the interface, you simply change the copywriting data in the dataset and notify the Flutter framework to trigger the Widget to rerender. This approach is much more convenient than the imperative view development approach, which requires setting the visual properties of different widgets one by one.

In summary, imperative programming emphasizes precise control of process details, while declarative programming emphasizes the overall output through intent. In The case of Flutter, the intent is bound to the State of the component, and the result is the rerendered component. Any changes applied to State during the Widget’s declaration cycle force the Widget to be rebuilt.

The binding of the state is optional for scenarios where there is no need to change the component after it has been created. “Optional” here distinguishes between two types of widgets: StatelessWidget with no bound state, and StatefulWidget with bound state. Choose to use the StatelessWidget when you are building a user interface that does not change with any state information, and StatefulWidget when you are not. The former is usually used for static content presentation, while the latter is used for content presentation with interactive feedback.

StatelessWidget

In Flutter, widgets are built from parent to child, top-down, with the parent Widget controlling the display style of the Widget, which is configured by the parent Widget at build time.

Some widgets built in this way (such as Text, Container, Row, Column, etc.) are created without relying on any information other than these configuration parameters. In other words, once created, they do not care and do not redraw in response to any data changes. In Flutter, such widgets are called stateless widgets.

Take part of the source code of Text as an example to illustrate the building process of StatelessWidget.
Class Text extends StatelessWidget {const Text(this.data, {key key, this.textalign, This. textDirection, // other parameters... }) : assert(data ! = null), textSpan = null, super(key: key); final string data; final TextAlign textAlign; final TextDirection textDirection; // Other attributes... @override Widget build(BuildContext context) { ... Widget result = RichText(// initial configuration...) ; .returnresult; }}Copy the code

As you can see in code, after the constructor assigns its property list, the build method initializes the child RichText with its property list (such as text data, alignment textAlign, text display direction, and so on) and returns. After that, the Text internally no longer responds to changes in external data.

So, in what application scenarios should you use statelessWidgets?

Simple rule: Does the parent Widget have full control over its UI presentation through initialization parameters? If so, you can use the StatelessWidget to design the constructor interface.

For example, the pop-up control for error messages can be customized by inheriting the StatelessWidget. Counter buttons need to be customized by inheriting the StatefulWidget.

StatefulWidget

In addition to the static configuration passed in when the parent Widget is initialized, the presentation of some widgets (such as Image, Checkbox) needs to handle user interactions (for example, the user clicking a button) or changes to its internal data (for example, network data packets) and be reflected in the UI. In other words, once these widgets are created, they need to care about and respond to data changes to redraw. In Flutter, this type of Widget is called a StatefulWidget.

StatefulWidget is implemented in a state-class proxy Widget architecture. Next, use part of the Image source code as an example to illustrate the StatefulWidget construction process.

As with Text above, the constructor of the Image class takes property arguments to be used by the class. However, the Image class does not have a build method to create the view. Instead, the createState method creates a state object of type _ImageState, which is then responsible for building the view.

This state object holds and handles state changes in the Image class, so let’s use the _imageInfo property as an example to illustrate this.

The _imageInfo property is used to load the actual image in the Widget. Once the State object listens to the _imageInfo property using the _handleImageChanged method, the _imageInfo property changes. The setState method of the _ImageStage class is immediately called to notify the Flutter framework: “The data has changed. Please reload the image with the updated _imageInfo data!” . The Flutter framework marks the state of the view and updates the UI.

Statefulwidgets are not a panacea, so use them with caution

In fact, the abuse of StatefulWidget can directly affect the rendering performance of the Flutter application.

Widgets are immutable, and updating means destroy + build. The StatelessWidget is static and does not need to be updated once created; For StateFulWidget, calling the setState method in the State class to update data triggers the destruction and reconstruction of the view and, indirectly, of each of its child widgets.

If the root layout is a StatefulWidget, each call to update the UI in its State will destroy and rebuild all the widgets on an entire page.

The interior of the Flutter uses the Element layer to minimize modifications to the real render view and improve rendering efficiency, rather than destroying the entire RenderObject tree to rebuild. However, the destruction and reconstruction of a large number of Widget objects is inevitable. If the rebuild of a sub-widget involves some time-consuming operations, the rendering performance of the page will suffer dramatically.

Therefore, properly evaluating view presentation requirements and avoiding unnecessary StatefulWidget use is the easiest and most direct way to improve the rendering performance of a Flutter application.