Flutter无法调用setState来重建小部件

时间:2019-06-04 14:10:26

标签: flutter dart

我对扑扑非常陌生,在线阅读的数百万答案使我更加困惑。这是我的页面:

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会破坏某些东西吗?

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

1 个答案:

答案 0 :(得分:3)

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

在这种情况下,我会使用吸气剂为您提供相同的便利,但始终使用当前_solver中的widget。然后,您可以报废initState

Algebraic get _solver => widget.solver;

另一个选择是didUpdateWidget,但实际上对于其他非常简单的事情来说,这里并没有必要。