#dart #flutter #state
#dart #флаттер #состояние
Вопрос:
У меня есть следующие переменные
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)
из другого класса, который реализует интерфейс
Комментарии:
1. Ну, эти значения в основном изменяются только классом _UserSignupInterface, поэтому, я думаю, можно с уверенностью сказать, что они изменены извне. Моя главная проблема заключается в изменении их состояния, поскольку мне действительно нужно изменить их в рамках реализованных методов интерфейса
2. извините, я нажал кнопку отправки в комментарии до того, как ответ был готов! 😀
3. Для тех, кто читает это и у кого возникает тот же вопрос. Узнайте, как использовать пакет provider, или пакет block, или другие пакеты управления состоянием. Это будет очень полезно, особенно в долгосрочной перспективе, и вам почти никогда не понадобится использовать setState снова. Новичкам может быть трудно понять, но поверьте мне. Этому очень стоит научиться, если вы планируете использовать flutter в течение длительного времени или в проектах среднего и крупного масштаба.
Ответ №1:
Вы должны решить, является ли это значением, которое изменяется внутри виджета, или это значение, которое изменяется по отношению к нему извне.
Если это внутренний, обычно их помещают в State
класс с _ на них, они могут начинаться, например, со значения, установленного на initState
, и каждый раз, когда они меняются, вы вызываете, setState
чтобы указать это.
Однако, если они изменяются вне виджета, то вы помещаете их в StatefulWidget
класс (как вы, кажется, и сделали), вы оставляете их без _, поскольку они на самом деле общедоступны, и вы даже делаете их окончательными и помещаете их в конструктор, чтобы разрешить их установку.
В этом последнем случае, если в State
классе вы должны быть осведомлены об изменении виджета, вы можете реализовать didUpdateWidget
, но это не обязательно.
Конечно, вы можете смешать обе вещи, имея _warningMessage
в State
, чтобы вы могли обновить его с помощью setState
, но с начальным значением, определенным в initState
, которое поступает из виджета.
Опять же, если виджет изменяется извне, вы можете снова обновить значение _warningMessage
новым значением widgets.
Что-то вроде этого: (я не тестировал этот код)
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. Спасибо, однако, я все еще немного сбит с толку. Потому что, если я использую set state, я получаю ошибку, которую я указал в своем вопросе. Должен ли я вызывать конструктор вместо setState?
2. Это сработало бы, поскольку я пробовал это раньше. Но, поскольку я использую класс, который реализует интерфейс, чтобы, надеюсь, управлять состоянием, он выдает мне ошибку. В вопросе указаны как интерфейс, так и ошибка. Но спасибо вам за помощь. Я все еще выясняю способы фактического изменения состояний из интерфейса
3. Затем поместите вашу переменную в UserSignupInterface, неправильно поместить ее в StatefulWidget.
Ответ №2:
Просто создайте статическое значение в состоянии вашего класса виджетов, затем, когда вы создадите виджет, установите его значение для виджета. Поэтому всякий раз, когда вы хотите вызвать его на setState()
, просто вызывайте статическое значение.