flutter runtime_error ai_generated true

setState() or markNeedsBuild() called during build

ID: flutter/setstate-or-initstate-async

Also available as: JSON · Markdown · 中文
92%Fix Rate
88%Confidence
1Evidence
2023-08-15First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
Flutter 3.10 active
Flutter 3.13 active
Flutter 3.16 active

Root Cause

A widget's build method or its dependencies triggered setState() synchronously, violating Flutter's single-frame build constraint.

generic

中文

Widget 的 build 方法或其依赖项同步触发了 setState(),违反了 Flutter 的单帧构建约束。

Official Documentation

https://api.flutter.dev/flutter/widgets/State/setState.html

Workarounds

  1. 95% success Use addPostFrameCallback to defer the setState call until after the current build frame: WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { /* update state */ }); });
    Use addPostFrameCallback to defer the setState call until after the current build frame:
    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() { /* update state */ });
    });
  2. 85% success Restructure widget to avoid calling setState during build. Move the triggering logic to initState or a separate event handler that runs after the initial layout.
    Restructure widget to avoid calling setState during build. Move the triggering logic to initState or a separate event handler that runs after the initial layout.
  3. 90% success If the update is from a stream or future, use a StreamBuilder or FutureBuilder to handle asynchronous state changes without manual setState.
    If the update is from a stream or future, use a StreamBuilder or FutureBuilder to handle asynchronous state changes without manual setState.

中文步骤

  1. Use addPostFrameCallback to defer the setState call until after the current build frame:
    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() { /* update state */ });
    });
  2. Restructure widget to avoid calling setState during build. Move the triggering logic to initState or a separate event handler that runs after the initial layout.
  3. If the update is from a stream or future, use a StreamBuilder or FutureBuilder to handle asynchronous state changes without manual setState.

Dead Ends

Common approaches that don't work:

  1. Wrapping the setState() call in a Future.delayed(Duration.zero) 40% fail

    Merely postpones the call to the next frame but does not address the root cause of calling setState during build.

  2. Moving setState() to initState() without checking lifecycle 50% fail

    initState() is called before build, but if the setState depends on BuildContext or inherited widgets not yet available, it can still cause issues.

  3. Using a global variable to track build state and skip setState 60% fail

    Brittle and error-prone; global state management often leads to other race conditions and missed updates.