如何在类/状态小部件外部调用setState?

时间:2019-04-01 12:24:08

标签: dart flutter state

我有以下变量

String _warningMessage;
bool _warningVisibility;

我想通过实现接口的类进行更新

class _UserSignupInterface extends _SignupSelectUsernamePageState
    implements UserSignupInterface {
  @override
  void onSuccess() {
    _hideWarning();
    _navigateToUserPage();
  }

  @override
  void onError(String message) {
    _isSignupClickable = true;

    if(message != null) {
      _displayWarning(message);
    }
  }
}

带有_displayWarning代码(位于_SignupSelectUsernamePageState内)

void _displayWarning(String message) {
    if (message != null) {
      setState(() {
        widget._warningMessage = message;
        widget._warningVisibility = true;
      });
    }
  }

但是,每当我从_displayWarning(message)外部呼叫_SignupSelectUsernamePageState时。我说错了

Unhandled Exception: setState() called in constructor

是否存在在类之外更新这些变量状态的正确方法?在我的情况下,我正在从实现接口的另一个类中调用_displayWarning(message)

3 个答案:

答案 0 :(得分:2)

您必须确定这是在窗口小部件内部内部更改的值,还是在外部对其进行更改的值。

如果是内部的,通常的做法是将它们放在带有{的_上的State类中,它们可以从initState上设置的实例值开始,并且每次更改时调用setState表示这一点。

但是,如果它们在窗口小部件外部更改,则将它们放置在StatefulWidget类上(就像您所做的一样),因为它们实际上是公共的,所以它们没有_,甚至使它们成为最终的并将它们放在构造函数中以进行设置。

在最后一种情况下,如果必须在State类中知道小部件中的更改,则可以实现didUpdateWidget,但这不是强制性的。

当然,您可以混合两种方式,在_warningMessage中使用State,因此可以使用setState进行更新,但要使用initState中定义的初始值来自小部件。

同样,如果窗口小部件在外部进行了更改,则可以再次使用新的窗口小部件值更新_warningMessage的值。

类似的东西:(我没有测试这段代码)

class YourWidget extends StatefulWidget {
  YourWidget({this.warningMessage});

  final String warningMessage;

  @override
  State<YourWidget> createState() => new _YourWidgetState();
}

class _YourWidgetState extends State<YourWidget> {
  String _warningMessage;

  @override
  void initState() {
    super.initState();
    _warningMessage = widget.warningMessage;
  }

  @override
  didUpdateWidget(ReorderableListSimple oldWidget) {
    super.didUpdateWidget(oldWidget);
    _warningMessage = widget.warningMessage;
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Text(_warningMessage),
        RaisedButton(
          child: Text("Change Message"),
          onPressed: () {
            setState(() {
              _warningMessage = "new message from within the State class";
            });
          }
        )
      ],
    );
  }
}

因此,在此示例中,您可以从外部更改warningMessage,就像在parent小部件中一样,您可以传递其他消息。但是,如果需要,您也可以在内部使用setState进行设置,就像按钮的onPressed一样。

您可能要检查的是,实际上您是否需要在Widget中公开该属性,也许您不需要!然后,该示例将如下所示:

class YourWidget extends StatefulWidget {
  @override
  State<YourWidget> createState() => new _YourWidgetState();
}

class _YourWidgetState extends State<YourWidget> {
  String _warningMessage;

  @override
  void initState() {
    super.initState();
    _warningMessage = "default message, no need for widget";
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Text(_warningMessage),
        RaisedButton(
          child: Text("Change Message"),
          onPressed: () {
            setState(() {
              _warningMessage = "new message from within the State class";
            });
          }
        )
      ],
    );
  }
}

答案 1 :(得分:0)

我通常只使用回调参数,然后将 (e) => setState((){ myField = e }) 作为参数传递给我正在调用的任何外部函数。

答案 2 :(得分:-1)

只需在窗口小部件类的状态中创建一个静态值,然后在构建窗口小部件时,将其值设置为窗口小部件即可。因此,只要您想将其调用为setState(),就只需调用静态值即可。