简体   繁体   中英

How does the stateful vs. stateless distinction affect when widgets will be rebuilt?

I am trying to understand how state and lifting state works in Flutter. In the code below I made a simple app where I tried to pass or lift a string and a function through multiple levels.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String data = 'MyApp class data';

  void setTextField(String s) {
    setState(
      () {
        data = s;
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MainApp(data, setTextField),
    );
  }
}

class MainApp extends StatelessWidget {
  final String mainAppData;
  final Function setTextField;
  MainApp(this.mainAppData, this.setTextField);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(mainAppData)),
      body: Container(
        child: Level2(mainAppData, setTextField),
      ),
    );
  }
}

class Level2 extends StatelessWidget {
  final String level2Data;
  final Function setTextField;
  Level2(this.level2Data, this.setTextField);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Level3(level2Data, setTextField),
    );
  }
}

class Level3 extends StatefulWidget {
  final String level3Data;
  final Function setTextField;
  Level3(this.level3Data, this.setTextField);

  @override
  _Level3State createState() {
    print('Level3: $this.level3Data');
    return _Level3State(this.level3Data, this.setTextField);
  }
}

class _Level3State extends State<Level3> {
  String level3Data;
  Function setTextField;
  _Level3State(this.level3Data, this.setTextField);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        TextField(
          onChanged: setTextField,
        ),
        Text(level3Data),
      ],
    );
  }
}

When the app starts, the string data in the _MyAppState state class is passed to the MainApp StatelessWidget when MainApp is built. In a similar manner, info is passed then to Level2 StatelessWidget and Level3 StatefulWidget.

When the TextField in Level3 changes, setTextField is triggered. setTextField is defined up in MyApp and I figured that when the String data changes (inside setState() ) it should trigger rebuilding of all the widgets affected by the change.

The text in the MainApp widget (appBar) changes, showing MainApp was rebuilt as I expected. But nothing happens to the Level3 widget; it's not rebuilt. The print statement in the createState() method does not execute, and the Text widget's text does not change.

Why doesn't the Level3 StatefulWidget rebuild?

In my understanding, the stateful widget Level3 is already created at the given location in the tree. And according to the contract of the stateful widget , It is the responsibility of the widget implementer to ensure that the State is promptly notified when such state changes, using State.setState. So in your case you need to have setstate in level3 to be notified of the change again. The rebuilding only happens at level 1 because setState is called.

The rebuilding process continues recursively until the description of the user interface is fully concrete. In Level 3, the class has its own set of fields String level3Data; Function setTextField; It means these need to be again set using SetState or if you do something like this then the widget building continues.

class Level3 extends StatefulWidget {
  final String level3Data;
  final Function setTextField;
  Level3(this.level3Data, this.setTextField);

  @override
  _Level3State createState() {
    print('Level3: $this.level3Data');
    return _Level3State();
  }
}

class _Level3State extends State<Level3> {
  // String level3Data;
  // Function setTextField;

  @override
  Widget build(BuildContext _) {
    return Column(
      children: <Widget>[
        TextField(
          onChanged: widget.setTextField,
        ),
        Text(widget.level3Data),
      ],
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM