Evil Mouth's Blog

flutter-StatelessWidget与StatefulWidget的解耦

June 13, 2018

StatelessWidgetStatefulWidgetflutter的基础组件,日常开发中自定义Widget都是选择继承这两者之一。

两者的区别在于状态的改变StatelessWidget面向那些始终不变的 UI 控件,比如标题栏中的标题;而StatefulWidget则是面向可能会改变 UI 状态的控件,比如有点击反馈的按钮。

StatelessWidget就没什么好研究的了,StatefulWidget的创建需要指定一个State,在需要更新 UI 的时候调用setState(VoidCallback fn),并在VoidCallback中改变一些变量数值等,组件会重新build以达到刷新状态也就是刷新 UI 的效果。

官方有个StatefulWidget的例子,通过点击按钮使屏幕上的Text数值逐渐增长,可以很好理解StatefulWidget的使用

class Counter extends StatefulWidget {
  // This class is the configuration for the state. It holds the
  // values (in this nothing) provided by the parent and used by the build
  // method of the State. Fields in a Widget subclass are always marked "final".

  
  _CounterState createState() => new _CounterState();
}

class _CounterState extends State<Counter> {
  int _counter = 0;

  void _increment() {
    setState(() {
      // This call to setState tells the Flutter framework that
      // something has changed in this State, which causes it to rerun
      // the build method below so that the display can reflect the
      // updated values. If we changed _counter without calling
      // setState(), then the build method would not be called again,
      // and so nothing would appear to happen.
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance
    // as done by the _increment method above.
    // The Flutter framework has been optimized to make rerunning
    // build methods fast, so that you can just rebuild anything that
    // needs updating rather than having to individually change
    // instances of widgets.
    return new Row(
      children: <Widget>[
        new RaisedButton(
          onPressed: _increment,
          child: new Text('Increment'),
        ),
        new Text('Count: $_counter'),
      ],
    );
  }
}

解耦

上面的例子比较简单,当层级多、状态多的情况下,这样的代码会导致阅读性、扩展性较低的不友好情况发生。代码整洁、代码解耦在日常开发中都非常重要,官方也是非常注重这一点,也提供了思路,将按钮和文本控件从Counter分离,Counter负责更新状态,按钮和文本控件只负责显示,这样达到了解耦,保持代码整洁,扩展性也对应提高。

class CounterDisplay extends StatelessWidget {
  CounterDisplay({this.count});

  final int count;

  
  Widget build(BuildContext context) {
    return new Text('Count: $count');
  }
}

class CounterIncrementor extends StatelessWidget {
  CounterIncrementor({this.onPressed});

  final VoidCallback onPressed;

  
  Widget build(BuildContext context) {
    return new RaisedButton(
      onPressed: onPressed,
      child: new Text('Increment'),
    );
  }
}

class Counter extends StatefulWidget {
  
  _CounterState createState() => new _CounterState();
}

class _CounterState extends State<Counter> {
  int _counter = 0;

  void _increment() {
    setState(() {
      ++_counter;
    });
  }

  
  Widget build(BuildContext context) {
    return new Row(children: <Widget>[
      new CounterIncrementor(onPressed: _increment),
      new CounterDisplay(count: _counter),
    ]);
  }
}

思考

好的编程思想对日常开发有非常大的帮助,官方只是提供一个很小的例子,仔细琢磨理清思路方能提高工作效率。

— Evil Mouth