Flutter. "setState() called during build" error

Ошибка "setState() called during build" в Flutter возникает, когда вы вызываете setState() во время перестройки дерева виджетов, что может привести к неожиданному поведению или бесконечным циклам.

Вот как можно решить эту проблему:

Возможные причины и решения:

  1. Вызов setState внутри метода build:

    • Убедитесь, что вы не вызываете setState() непосредственно внутри метода build(). setState должен вызываться в ответ на взаимодействие пользователя или асинхронное событие (например, сетевой запрос).

      Пример:

      @override
      Widget build(BuildContext context) {
        // Неправильно: setState вызывается напрямую в build
        if (someCondition) {
          setState(() {
            // изменение состояния
          });
        }
        
        return Scaffold(
          // код UI
        );
      }
      

      Решение: Перенесите изменение состояния в подходящее место, например, в обработчик события или после получения результата асинхронной операции.

  2. Асинхронные изменения состояния:

    • Если вы вызываете setState() в асинхронной операции, такой как FutureBuilder или внутри метода then(), убедитесь, что виджет не перестраивается в тот момент, когда вызывается setState.

      Пример:
      Future<void> someAsyncFunction() async {
        final result = await someFuture;
        setState(() {
          // обновление состояния здесь
        });
      }
      

      Решение: Убедитесь, что setState вызывается после завершения асинхронной операции, но вне контекста метода build.

  3. Таймеры или слушатели событий:
    Если вы используете Timer, AnimationController или другие слушатели событий, убедитесь, что setState() вызывается в ответ на событие, но не во время перестройки виджета.

    Пример:

    Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() {
        // обновление состояния
      });
    });
    

    Решение: Используйте их безопасным образом, проверяя, что виджет всё ещё существует (mounted), или корректно отменяйте таймеры/слушатели, когда виджет уничтожается.

Резюме решений:

  • Не вызывайте setState() внутри метода build().
  • Вызывайте setState() после завершения асинхронных операций.
  • Для периодических изменений состояния (таймеры, анимации) убедитесь, что виджет всё ещё существует перед вызовом setState().