为什么人们将 TabController 放在 initState 中,而将它放在 Widget build 中却可以正常工作?

Why do people put TabController inside initState when putting it inside Widget build does the work just fine?

我看到的很多教程总是把 TabController 放在 initState 里面,像这样:
(示例教程:TabBar Widget in flutter

TabController _tabController;

void initState() {
  super.initState();
  _tabController = TabController(length: 3, vsync: this);
}

但是 none 已经解释了为什么,当下面的例子工作正常时:

TabController _tabController;

Widget build(BuildContext context) {
  _tabController = TabController(length: 3, vsync: this);
  ...
}

将它放在 initState 而不是 Widget build 中有什么好处吗?

我问这个是因为我想为 TabController 长度使用提供程序,如果我将 TabController 放在 initState 中就不能这样做, 所以现在我正在做的是:

TabController _tabController;

Widget build(BuildContext context) {
  _tabController = TabController(length: Provider.of<List>(context).listLength, vsync: this);
  ...
}

而且我想知道是否存在已知错误或人们将 TabController 置于 initState 中的任何原因。

因为initState只运行一次,在创建组件时,build会在每次渲染组件时运行,所以如果在build里面初始化state,就是在初始化state每次。

这里有一个例子,BuildWidget 会在每次渲染时改变它的值,而 StateWidget 只会在初始化时改变它的值。

class BuildWidget extends StatefulWidget {
  const BuildWidget({Key? key}) : super(key: key);

  @override
  _BuildWidgetState createState() => _BuildWidgetState();
}

class _BuildWidgetState extends State<BuildWidget> {
  final Random _random = Random();
  int _value = 0;
  @override
  Widget build(BuildContext context) {
    _value = _random.nextInt(100);
    return Center(
      child: Text('My value is $_value'),
    );
  }
}

class StateWidget extends StatefulWidget {
  const StateWidget({Key? key}) : super(key: key);

  @override
  _StateWidgetState createState() => _StateWidgetState();
}

class _StateWidgetState extends State<StateWidget> {
  final Random _random = Random();
  int _value = 0;
  @override
  void initState() {
    _value = _random.nextInt(100);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('My value is $_value'),
    );
  }
}