Могу ли я расширить класс состояния и переопределить setState

#flutter #flutter-layout #flutter-dependencies

#flutter #flutter-layout #flutter-зависимости

Вопрос:

Я продолжал сталкиваться с проблемой, из-за которой вы вызываете setState , когда виджет не смонтирован (особенно после выборки данных). Мой вопрос:

Могу ли я расширить State класс и переопределить setState вот так

 abstract class MountedState<T extends StatefulWidget> extends State<T> {
  @override
  void setState(fn) {
    if(mounted) super.setState(fn);
  }
}
  

Я сделал это, и это сработало. Я просто хочу знать, не идеально ли это, или я не должен

 Future<void> fetchSubjectsAndClasses() async {
    try {
      Response res = await TeachersAPI.classesAndSubjects();
      classes = res.data;
      setState(() {});
    } catch (e) {
      print(e);
    }
  }
  

Это моя выборка данных, которая вызывает проблему. Он вызывается на initState

Комментарии:

1. Если вы постоянно вызываете setState , когда виджет не смонтирован, вы, вероятно, делаете что-то неправильно.

2. Я думаю, как @ChristopherMoore. Обычно этого не должно происходить.

3. Он вызывается не последовательно setState . У меня есть виджеты, которые делают сетевые запросы для получения данных. Затем вызовите setState после извлечения данных. Но пользователь, возможно, изменил маршрут до того, как данные были возвращены. В котором затем будет вызван setState, но, конечно, виджет больше не доступен, поэтому он выдает ошибку @ChristopherMoore @NiklasLehnfeld

4.Я не говорил, что вы постоянно вызываете setState . Я сказал, что вы постоянно звонили, setState когда виджет не смонтирован. Из того, что я могу сказать, вы, похоже, выполняете какой-то асинхронный вызов без FutureBuilder , у которого нет проблем, которые вы описываете. Вам нужно поделиться тем, что вы делаете, что генерирует ошибки без вашего специального класса.

5. Я извлекаю данные без FutureBuilder . Затем обновляю пользовательский интерфейс, как только я закончу выборку

Ответ №1:

Это не идеально. Вы должны использовать FutureBuilder при работе с асинхронными функциями, которые имеют дело с пользовательским интерфейсом. Это не обязательно, но оно устраняет более раздражающие части обновления пользовательского интерфейса с Future данными.

Вы должны получить свое будущее в initState и сохранить его в State виджете. Затем передайте это вашему FutureBuilder в build :

 Future myFuture;

@override
void initState() {
  super.initState();
   myFuture = futureCall();
}

@override
Widget build() {
  return FutureBuilder(
    future: myFuture,
    builder: (BuildContext context, AsyncSnapshot snapshot) {
      if (snapshot.hasData) {
        //Show widget that has data
      }
      else if (snapshot.hasError) {
        //Show widget that has error
      }
      else {
        //Show widget while loading
      }
    }
  );
}
  

Комментарии:

1. Хорошо, спасибо! Однако, есть ли какая-либо причина, по которой я не должен использовать метод, описанный в моем вопросе?

2. @NduJay Это предотвращает проблемы, подобные той, с которой вы сталкиваетесь в настоящее время, и это значительно проще практически во всех ситуациях. Это также может быть более эффективным в зависимости от элементов окружения.

3. Да, я это понимаю. Например, решение также предотвращает эти проблемы, и я могу легко использовать его в своем виджете, расширив мой MountedState вместо State . Есть ли какая-либо конкретная причина, по которой я не должен использовать пользовательский MountedState класс. Еще раз спасибо

4. @NduJay Это значительно проще в использовании и может быть более эффективным. Кроме того, ваша текущая проверка может не сработать, если виджет уничтожается и еще не размонтирован.

5. @NduJay То, что вы делаете, не неправильно , но это шаблонно.