Statefulwidgets and StatelessWidgets should be familiar to anyone who has touched Flutter. Everyone knows that almost all objects in Flutter are widgets. Unlike the “controls” in native development, the concept of widgets in Flutter is broader. Widgets can represent not only UI elements but also functional components such as: GestureDetector widgets for gesture detection, themes for APP Theme data delivery, and so on, while controls in native development usually just refer to UI elements. Statefulwidgets and StatelessWidgets inherit from the Widget class.

  • Differences and concepts between StatelessWidgets and StatefulWidgets
  1. StatelessWidget is used to describe situations where the widget is of stateless type and does not need to maintain state. It typically builds the UI by nesting other widgets in the build method, recursively building its nested widgets during the build process. It doesn’t change over the life cycle.
  2. StatefulWidget is used to describe the type of widget as stateful, which is a bit more complicated to describe. Let’s first look at the definition of StatefulWidget
class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);

  @override
  StatefulElement createElement() => new StatefulElement(this);

  @protected
  State createState();
}
Copy the code

A new interface createState() has been added to the StatefulWidget class, CreateState () may be called several times during the StatefulElement() method execution to create a State object. CreateState () is used to create states associated with Statefulwidget. It could be called several times in the life cycle of Stateful Widgets. For example, when a Stateful widget was inserted into multiple locations in the widget tree at the same time, the Flutter Framework would call this method to generate an independent State instance for each location. Essentially, a StatefulElement corresponds to a State instance. One StatefulWidget class corresponds to another State class. State represents the State to be maintained by the corresponding StatefulWidget. The StatefulWidget class itself is unchanged, but the State class is always present throughout the Widget’s life cycle. If you want to change the page, you essentially call the setState() method in the State class, and then execute the Build () method again to refresh the UI. Take a look at the State lifecycle to better understand how StatefulWidget implements refresh widgets

class _CounterWidgetState extends State<CounterWidget> {  
  int _counter;

  @override
  void initState() { super.initState(); // Initializing state _counter=widget.initValue;print("initState");
  }

  @override
  Widget build(BuildContext context) {
    print("build");
    return Scaffold(
      body: Center(
        child: FlatButton(
          child: Text('$_counter'), // the counter is pressed :()=>setState(()=> ++_counter,
          ),
        ),
      ),
    );
  }

  @override
  void didUpdateWidget(CounterWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("didUpdateWidget");
  }

  @override
  void deactivate() {
    super.deactivate();
    print("deactive");
  }

  @override
  void dispose() {
    super.dispose();
    print("dispose");
  }

  @override
  void reassemble() {
    super.reassemble();
    print("reassemble");
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("didChangeDependencies"); }}Copy the code

This is the life cycle of State, and other methods are not explained here. If you are interested in or still do not understand State, you can specifically search for articles about State to learn, which can help you better understand this part of the content.

In addition, you may notice that each build method has a context parameter, which is an instance of the BuildContext class and represents the context of the current widget in the Widget tree. Each widget has a context object. Ontext is a handle to perform “related actions” on the current widget at its location in the widget tree. It provides methods for traversing the widget up the tree from the current widget and finding the parent widget by widget type.

class ContextRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("The Context test"), ), body: Container( child: Builder(builder: (context) {// Look up the most recent parent 'Scaffold' in the Widget tree context.findAncestorWidgetOfExactType<Scaffold>(); // Returns the title of the AppBar directly, which is actually Text("The Context test")
          return(scaffold.appBar as AppBar).title; }),),); }}Copy the code

The simple generalization is that you can use the context parameter in a subclass to get information from the parent. You should have a general idea, but I’m not going to go into details here, but I’ll probably write an article in the future that will explain some of the uses of Context, and BuildContext in more detail.

Conclusion: Because I want to explain their concepts and differences with you in a professional perspective as much as possible, some friends who are new to FLUTTER may not understand what I say or have no patience to read my long discussion above. So you can just look at my summary here. Here I give a general overview of their differences and usage scenarios. StatelessWidget is a StatelessWidget that cannot be changed after initialization and can be used to display static pages such as text or images. A StatefulWidget describes a StatefulWidget that can change the state of the widget, such as a network request to refresh a list, or clicking a button to change the text content.

  • 2. Don’t abuse StatefulWidget

    Some beginners ask why use a StatelessWidget when StatefulWidget is so powerful and they should just use it. This brings us to the second point in this article, which is that StatefulWidget is not a cure-all. While it may seem powerful, it can also be costly internally if abused.

    As mentioned in the previous article, to change a widget, call the setState() method, which launches state.build. But this also indirectly triggers the constructor and build methods for each child control. If your root layout is a StatefulWidget, every time you call setState() in the root State, All widgets will be rebuilt to the entire page at once. In layman’s terms, this is close to recreating your widgets, but this is just to make it easier for people to understand. Don’t think of it as recreating, because there are some differences. Let me give you an example.

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page')); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void_incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '1111111',
            ),
            Text(
              '222222',
            ),
            Text(
              '333333 -' + _counter.toString(),
            ),
            TestCirculating()
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class TestCirculating extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    for (int i = 0; i < 200; i++) {
      print("Simulating time-consuming operation :" + i.toString());
    }
    return Container(
      child: Text("4444444")); }}Copy the code

We wrote a small demo using the build Flutter engineering system, and then simulated time-consuming actions to visualize the consequences of misusing a StatefulWidget. Click the + button, and the 0 after the third line of text will add a +1 each time you click it

Now mobile phone performance is very good, I simulated a for loop for the temporary use of mobile phone resources can be said to be very small, just to let everyone understand this truth, real projects may encounter a lot of data, if the whole page is re-executed, it will occupy a lot of mobile phone resources. To better understand this, think of the root widget as a big tree and the child controls as branches on the tree. If you want to shake one of the branches, there are two ways, one is to shake the tree, or you can shake the branch you want to shake alone. The method I described above is the first method of shaking the tree, which is obviously not desirable and will cause a lot of energy consumption. So all we need to do is shake a branch separately, pull out the control separately, and the parent inherits from the StatelessWidget. The control that needs to be changed inherits from the StatefulWidget class separately, and then refresh a separate control.