StatelessWidget与StatefulWidget的选择

  • 优先选择StatelessWidget。
  • 对于需要Widget自行维护状态,而这个状态又不需要暴露给父Widget的,使用StatefulWidget。其中状态定义在State中,而非StatefulWidget中。
  • 父Widget传给子Widget数据,有两种情况:
    1. 父Widget同时传入数据更新函数。当子Widget操作数据更新时,调用此函数。父Widget必须是StatefulWidget。
    2. 子Widget自行维护数据的更新和显示。子Widget必须是StatefulWidget。

方式一: 父Widget负责数据更新维护

首先定义父Widget:

class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() => new _ParentWidgetState();
}

class _ParentWidgetState extends State {
  bool _active = false;

  void updateValue(bool newValue) {
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ChildWidget(
      active: _active,
      parentUpdate: updateValue,
    );
  }
}

然后定义子Widget:

class ChildWidget extends StatefulWidget {
  bool active;
  Function parentUpdate;

  ChildWidget({Key key, this.active: false, @required this.parentUpdate}) : super(key: key);

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

class _ChildWidgetState extends State {
  @override
  Widget build(BuildContext context) {
    return new Column(
      children: [
        Text(widget.active ? 'Active' : 'Inactive'),
        RaisedButton(
          child: Text('change active'),
          onPressed: () {
            widget.parentUpdate(!widget.active);
          },
        )
      ],
    );
  }
}

如上。父Widget将数据和更新函数同时传给了子Widget。子Widget的显示依赖于该数据。
当对子Widget进行操作,需要更改显示内容时,子Widget调用父Widget的更新函数即可。父Widget对数据更改并触发更新。子Widget判定可复用,然后用新的Widget数据更新自身。于是子Widget的显示得以更新。

方式二: 子Widget负责数据更新维护

首先定义父Widget:

class ParentWidget extends StatelessWidget {
  ParentWidget({Key key}) : super(key: key);

  final bool active;

  @override
  Widget build(BuildContext context) {
    return ChildWidget(
      active: active,
    );
  }
}

然后定义子Widget:

class ChildWidget extends StatefulWidget {
  bool active;

  ChildWidget({Key key, this.active: false}) : super(key: key);

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

class _ChildWidgetState extends State {
  @override
  Widget build(BuildContext context) {
    return new Column(
      children: [
        Text(widget.active ? 'Active' : 'Inactive'),
        RaisedButton(
          child: Text('change active'),
          onPressed: () {
            setState(() {
              widget.active = !widget.active;
            });
          },
        )
      ],
    );
  }
}

如上。父Widget将数据传给了子Widget。子Widget的显示依赖于该数据。
当对子Widget进行操作,需要更改显示内容时,子Widget调用自身的更新函数来修改数据值。
在此情形下,父Widget可以是StatelessWidget/StatefulWidget。
注意上面直接用widget.xx来使用/修改数据。对于父Widget传入的数据,推荐使用此方式,而不是在State中再次定义一个变量来再次接收。

StatefulWidget的维护方式选择

对于上面两种方式,对应不同的需求场景。通常来说:

  1. 若父Widget的数据影响到多个子Widget,即某个子Widget修改了数据后,多个子Widget都会同步更新,那么必须让父Widget来维护数据更新,也就是上面方式一。
  2. 若父Widget的数据只影响到单个子Widget,也就是说子Widget修改了数据后,只有自身会更新,那么推荐子Widget自行维护,也就是上面方式二。

对逻辑而言,两种方式都可以实现更改父Widget中数据的目的。区别在于更改数据后,谁负责将这个改动体现在界面上。
通常来说,2是最常见的。且2中父Widget可以是StatelessWidget/StatefulWidget。常规开发推荐使用2。
若不得不采用1,则父Widget必须是StatefulWidget,因为要提供修改函数。

你可能感兴趣的:(Flutter,Dart)