【问题标题】:Flutter cannot call setState to rebuild widgetFlutter 无法调用 setState 重建小部件
【发布时间】:2021-06-07 20:27:13
【问题描述】:

我对 Flutter 很陌生,我在网上阅读的数百万个答案让我更加困惑。这是我的页面:

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

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

class SecondDegreePageState extends State<SecondDegreePage> {

  final GlobalKey<FormState> _formKey = new GlobalKey();

  final controllerParamA = TextEditingController();
  final controllerParamB = TextEditingController();
  final controllerParamC = TextEditingController();

  Quadratic _solver = Quadratic([
    (Random().nextInt(10) + 1) * 1.0,
    (Random().nextInt(10) + 1) * 1.0,
    (Random().nextInt(10) + 1) * 1.0
  ]);

  void updateData() {
    setState(() {
      _solver = Quadratic([
        (Random().nextInt(10) + 1) * 1.0,
        (Random().nextInt(10) + 1) * 1.0,
        (Random().nextInt(10) + 1) * 1.0
      ]);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(AppLocalization.of(context).title),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: <Widget>[

          // Input form
          Form(
            key: _formKey,
            child: Padding(
              padding: EdgeInsets.all(20),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  EquationInputField(
                    controller: controllerParamA,
                    textHint: 'a',
                    width: 70,
                  ),
                  EquationInputField(
                    controller: controllerParamB,
                    textHint: 'b',
                    width: 70,
                  ),
                  EquationInputField(
                    controller: controllerParamC,
                    textHint: 'c',
                    width: 70,
                  ),
                ],
              ),
            ),
          ),

          // Submit button
          Padding(
            padding: EdgeInsets.fromLTRB(0, 30, 0, 30),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  onPressed: () => updateData(),
                  color: Colors.blue,
                  elevation: 6,
                  child: Text(
                    AppLocalization.of(context).solve,
                    style: TextStyle(
                        color: Colors.white
                    ),
                  ),
                )
              ],
            ),
          ),

          //Solutions
          Expanded(
            child: Padding(
              padding: EdgeInsets.only(bottom: 10),
              child: AlgebraicSolutions(
                solver: _solver
                ),
              ),
            ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    controllerParamA.dispose();
    controllerParamB.dispose();
    controllerParamC.dispose();

    super.dispose();
  }
}

Quadratic 类型只是一个做一些数学运算的类,没有什么重要的。问题出在这一行:

RaisedButton(
  onPressed: () => updateData()
}

为什么什么也没发生?我已经阅读了对 setState 的调用调用了 build 方法,并且重新构建了小部件。因此,我希望

child: AlgebraicSolutions(
  solver: _solver
),

这里_solver 参考得到更新。 AlgebraicSolutions 如下:

class AlgebraicSolutions extends StatefulWidget {

  final Algebraic solver;

  const AlgebraicSolutions({Key key, @required this.solver}) : super(key: key);

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

class AlgebraicSolutionsState extends State<AlgebraicSolutions> {

  //'Quadratic' is a subtype of Algebraic
  Algebraic _solver;

  @override
  void initState() {
    _solver = widget.solver;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    var solutions = _solver.solve();

    return ListView.builder(
      itemCount: solutions.length,
      itemBuilder: (context, index) {
        //...
      }
    );
  }

}

那是因为我在 AlgebraicSolutionsState 中使用 initState 会破坏某些东西吗?

请注意,二次型是代数型的子类。

【问题讨论】:

  • 会不会是因为我在分开的页面中有小部件?

标签: flutter dart


【解决方案1】:

是的,将初始值保存在 initState 中会给您带来麻烦。该生命周期方法仅在首次构建时调用,但由于小部件与兼容类型协调,因此使用相同的状态。即属性更改(小部件实例不同)但状态是相同的对象。 build 被再次调用,但 initState 没有。

在这种情况下,我会使用 getter 为您提供同样的便利,但始终使用当前 widget 中的 _solver。然后你可以丢弃initState

Algebraic get _solver => widget.solver;

另一个选项是didUpdateWidget,但这里真的不需要这么简单的东西。

【讨论】:

  • 好的,我可以放那个 getter,但是我该如何更新 _solver 对象呢?
  • 没必要,这就是getter的美妙之处。在AlgebraicSolutionsState 中,任何时候你使用_solver 它实际上都会给你widget.solver。请注意,它是一个函数 (=&gt;),因此它只会在被询问后查找 widget。这意味着您始终使用最新的widget,因此solver
猜你喜欢
  • 1970-01-01
  • 2019-03-16
  • 2020-09-26
  • 2021-09-19
  • 2021-06-13
  • 1970-01-01
  • 2020-09-20
  • 2020-08-02
  • 2021-11-17
相关资源
最近更新 更多