[{"data":1,"prerenderedAt":4295},["ShallowReactive",2],{"page-\u002Fdart\u002F16-flutter-essentials":3},{"id":4,"title":5,"body":6,"description":4288,"extension":4289,"meta":4290,"navigation":57,"path":4291,"seo":4292,"stem":4293,"__hash__":4294},"content\u002Fdart\u002F16-flutter-essentials.md","Dart — Flutter Widget Architecture & State Lifecycle",{"type":7,"value":8,"toc":4272},"minimark",[9,13,23,598,605,1324,1331,1848,1858,2476,2483,3082,3086,3694,3698,3787,3791,3952,3956,3966,4039,4042,4268],[10,11,5],"h1",{"id":12},"dart-flutter-widget-architecture-state-lifecycle",[14,15,17,18,22],"h2",{"id":16},"widget-tree-const-canonicalization-rebuild-performance","Widget Tree — ",[19,20,21],"code",{},"const"," Canonicalization & Rebuild Performance",[24,25,27],"code-wrapper",{"language":26},"dart",[28,29,33],"pre",{"className":30,"code":31,"language":26,"meta":32,"style":32},"language-dart shiki shiki-themes github-light github-dark","import 'package:flutter\u002Fmaterial.dart';\n\n\u002F\u002F ── const widgets are canonicalized — zero allocation, zero rebuild ──\n\u002F\u002F The framework reuses the same instance. Mark every static widget const.\n\n\u002F\u002F ❌ Anti-pattern: non-const widgets in hot paths (rebuilds allocate + diff).\nclass BadList extends StatelessWidget {\n  const BadList({super.key});\n  @override\n  Widget build(BuildContext context) {\n    return ListView(\n      children: [\n        Text('Header'),        \u002F\u002F ← allocates a new Text each build\n        Text('Item 1'),        \u002F\u002F ← allocates again\n        Icon(Icons.star),      \u002F\u002F ← allocates again\n      ],\n    );\n  }\n}\n\n\u002F\u002F ✓ Correct: const widgets — canonicalized, reused, zero rebuild cost.\nclass GoodList extends StatelessWidget {\n  const GoodList({super.key});\n  @override\n  Widget build(BuildContext context) {\n    return ListView(\n      children: const [\n        Text('Header'),        \u002F\u002F ← same instance every build (const)\n        Text('Item 1'),        \u002F\u002F ← same instance\n        Icon(Icons.star),      \u002F\u002F ← same instance\n      ],\n    );\n  }\n}\n\n\u002F\u002F ── const constructors enable const widgets ──\n\u002F\u002F A widget with a const constructor can be instantiated as const\n\u002F\u002F if all arguments are const-eligible.\nclass Greeting extends StatelessWidget {\n  final String name;\n  const Greeting({super.key, required this.name});  \u002F\u002F const constructor\n\n  @override\n  Widget build(BuildContext context) {\n    return Text('Hello, $name');\n  }\n}\n\n\u002F\u002F const usage — all args are compile-time constants:\nconst greeting = Greeting(name: 'World');  \u002F\u002F canonicalized\n\n\u002F\u002F Non-const — runtime value, allocates:\nfinal dynamicGreeting = Greeting(name: DateTime.now().toString());  \u002F\u002F can't be const\n","",[19,34,35,52,59,66,72,77,83,102,119,125,144,156,168,185,200,216,222,228,234,240,245,251,265,278,283,296,305,317,331,345,358,363,368,373,378,383,389,395,401,415,427,453,458,463,476,501,506,511,516,522,549,554,560],{"__ignoreMap":32},[36,37,40,44,48],"span",{"class":38,"line":39},"line",1,[36,41,43],{"class":42},"svdQ7","import",[36,45,47],{"class":46},"sJ6F3"," 'package:flutter\u002Fmaterial.dart'",[36,49,51],{"class":50},"ssxIu",";\n",[36,53,55],{"class":38,"line":54},2,[36,56,58],{"emptyLinePlaceholder":57},true,"\n",[36,60,62],{"class":38,"line":61},3,[36,63,65],{"class":64},"sdCPZ","\u002F\u002F ── const widgets are canonicalized — zero allocation, zero rebuild ──\n",[36,67,69],{"class":38,"line":68},4,[36,70,71],{"class":64},"\u002F\u002F The framework reuses the same instance. Mark every static widget const.\n",[36,73,75],{"class":38,"line":74},5,[36,76,58],{"emptyLinePlaceholder":57},[36,78,80],{"class":38,"line":79},6,[36,81,82],{"class":64},"\u002F\u002F ❌ Anti-pattern: non-const widgets in hot paths (rebuilds allocate + diff).\n",[36,84,86,89,93,96,99],{"class":38,"line":85},7,[36,87,88],{"class":42},"class",[36,90,92],{"class":91},"snvgF"," BadList",[36,94,95],{"class":42}," extends",[36,97,98],{"class":91}," StatelessWidget",[36,100,101],{"class":50}," {\n",[36,103,105,108,110,113,116],{"class":38,"line":104},8,[36,106,107],{"class":42},"  const",[36,109,92],{"class":91},[36,111,112],{"class":50},"({",[36,114,115],{"class":91},"super",[36,117,118],{"class":50},".key});\n",[36,120,122],{"class":38,"line":121},9,[36,123,124],{"class":42},"  @override\n",[36,126,128,131,135,138,141],{"class":38,"line":127},10,[36,129,130],{"class":91},"  Widget",[36,132,134],{"class":133},"sIsaT"," build",[36,136,137],{"class":50},"(",[36,139,140],{"class":91},"BuildContext",[36,142,143],{"class":50}," context) {\n",[36,145,147,150,153],{"class":38,"line":146},11,[36,148,149],{"class":42},"    return",[36,151,152],{"class":91}," ListView",[36,154,155],{"class":50},"(\n",[36,157,159,162,165],{"class":38,"line":158},12,[36,160,161],{"class":50},"      children",[36,163,164],{"class":42},":",[36,166,167],{"class":50}," [\n",[36,169,171,174,176,179,182],{"class":38,"line":170},13,[36,172,173],{"class":91},"        Text",[36,175,137],{"class":50},[36,177,178],{"class":46},"'Header'",[36,180,181],{"class":50},"),        ",[36,183,184],{"class":64},"\u002F\u002F ← allocates a new Text each build\n",[36,186,188,190,192,195,197],{"class":38,"line":187},14,[36,189,173],{"class":91},[36,191,137],{"class":50},[36,193,194],{"class":46},"'Item 1'",[36,196,181],{"class":50},[36,198,199],{"class":64},"\u002F\u002F ← allocates again\n",[36,201,203,206,208,211,214],{"class":38,"line":202},15,[36,204,205],{"class":91},"        Icon",[36,207,137],{"class":50},[36,209,210],{"class":91},"Icons",[36,212,213],{"class":50},".star),      ",[36,215,199],{"class":64},[36,217,219],{"class":38,"line":218},16,[36,220,221],{"class":50},"      ],\n",[36,223,225],{"class":38,"line":224},17,[36,226,227],{"class":50},"    );\n",[36,229,231],{"class":38,"line":230},18,[36,232,233],{"class":50},"  }\n",[36,235,237],{"class":38,"line":236},19,[36,238,239],{"class":50},"}\n",[36,241,243],{"class":38,"line":242},20,[36,244,58],{"emptyLinePlaceholder":57},[36,246,248],{"class":38,"line":247},21,[36,249,250],{"class":64},"\u002F\u002F ✓ Correct: const widgets — canonicalized, reused, zero rebuild cost.\n",[36,252,254,256,259,261,263],{"class":38,"line":253},22,[36,255,88],{"class":42},[36,257,258],{"class":91}," GoodList",[36,260,95],{"class":42},[36,262,98],{"class":91},[36,264,101],{"class":50},[36,266,268,270,272,274,276],{"class":38,"line":267},23,[36,269,107],{"class":42},[36,271,258],{"class":91},[36,273,112],{"class":50},[36,275,115],{"class":91},[36,277,118],{"class":50},[36,279,281],{"class":38,"line":280},24,[36,282,124],{"class":42},[36,284,286,288,290,292,294],{"class":38,"line":285},25,[36,287,130],{"class":91},[36,289,134],{"class":133},[36,291,137],{"class":50},[36,293,140],{"class":91},[36,295,143],{"class":50},[36,297,299,301,303],{"class":38,"line":298},26,[36,300,149],{"class":42},[36,302,152],{"class":91},[36,304,155],{"class":50},[36,306,308,310,312,315],{"class":38,"line":307},27,[36,309,161],{"class":50},[36,311,164],{"class":42},[36,313,314],{"class":42}," const",[36,316,167],{"class":50},[36,318,320,322,324,326,328],{"class":38,"line":319},28,[36,321,173],{"class":91},[36,323,137],{"class":50},[36,325,178],{"class":46},[36,327,181],{"class":50},[36,329,330],{"class":64},"\u002F\u002F ← same instance every build (const)\n",[36,332,334,336,338,340,342],{"class":38,"line":333},29,[36,335,173],{"class":91},[36,337,137],{"class":50},[36,339,194],{"class":46},[36,341,181],{"class":50},[36,343,344],{"class":64},"\u002F\u002F ← same instance\n",[36,346,348,350,352,354,356],{"class":38,"line":347},30,[36,349,205],{"class":91},[36,351,137],{"class":50},[36,353,210],{"class":91},[36,355,213],{"class":50},[36,357,344],{"class":64},[36,359,361],{"class":38,"line":360},31,[36,362,221],{"class":50},[36,364,366],{"class":38,"line":365},32,[36,367,227],{"class":50},[36,369,371],{"class":38,"line":370},33,[36,372,233],{"class":50},[36,374,376],{"class":38,"line":375},34,[36,377,239],{"class":50},[36,379,381],{"class":38,"line":380},35,[36,382,58],{"emptyLinePlaceholder":57},[36,384,386],{"class":38,"line":385},36,[36,387,388],{"class":64},"\u002F\u002F ── const constructors enable const widgets ──\n",[36,390,392],{"class":38,"line":391},37,[36,393,394],{"class":64},"\u002F\u002F A widget with a const constructor can be instantiated as const\n",[36,396,398],{"class":38,"line":397},38,[36,399,400],{"class":64},"\u002F\u002F if all arguments are const-eligible.\n",[36,402,404,406,409,411,413],{"class":38,"line":403},39,[36,405,88],{"class":42},[36,407,408],{"class":91}," Greeting",[36,410,95],{"class":42},[36,412,98],{"class":91},[36,414,101],{"class":50},[36,416,418,421,424],{"class":38,"line":417},40,[36,419,420],{"class":42},"  final",[36,422,423],{"class":91}," String",[36,425,426],{"class":50}," name;\n",[36,428,430,432,434,436,438,441,444,447,450],{"class":38,"line":429},41,[36,431,107],{"class":42},[36,433,408],{"class":91},[36,435,112],{"class":50},[36,437,115],{"class":91},[36,439,440],{"class":50},".key, ",[36,442,443],{"class":42},"required",[36,445,446],{"class":91}," this",[36,448,449],{"class":50},".name});  ",[36,451,452],{"class":64},"\u002F\u002F const constructor\n",[36,454,456],{"class":38,"line":455},42,[36,457,58],{"emptyLinePlaceholder":57},[36,459,461],{"class":38,"line":460},43,[36,462,124],{"class":42},[36,464,466,468,470,472,474],{"class":38,"line":465},44,[36,467,130],{"class":91},[36,469,134],{"class":133},[36,471,137],{"class":50},[36,473,140],{"class":91},[36,475,143],{"class":50},[36,477,479,481,484,486,489,492,495,498],{"class":38,"line":478},45,[36,480,149],{"class":42},[36,482,483],{"class":91}," Text",[36,485,137],{"class":50},[36,487,488],{"class":46},"'Hello, ",[36,490,491],{"class":46},"$",[36,493,494],{"class":91},"name",[36,496,497],{"class":46},"'",[36,499,500],{"class":50},");\n",[36,502,504],{"class":38,"line":503},46,[36,505,233],{"class":50},[36,507,509],{"class":38,"line":508},47,[36,510,239],{"class":50},[36,512,514],{"class":38,"line":513},48,[36,515,58],{"emptyLinePlaceholder":57},[36,517,519],{"class":38,"line":518},49,[36,520,521],{"class":64},"\u002F\u002F const usage — all args are compile-time constants:\n",[36,523,525,527,530,533,535,538,540,543,546],{"class":38,"line":524},50,[36,526,21],{"class":42},[36,528,529],{"class":50}," greeting ",[36,531,532],{"class":42},"=",[36,534,408],{"class":91},[36,536,537],{"class":50},"(name",[36,539,164],{"class":42},[36,541,542],{"class":46}," 'World'",[36,544,545],{"class":50},");  ",[36,547,548],{"class":64},"\u002F\u002F canonicalized\n",[36,550,552],{"class":38,"line":551},51,[36,553,58],{"emptyLinePlaceholder":57},[36,555,557],{"class":38,"line":556},52,[36,558,559],{"class":64},"\u002F\u002F Non-const — runtime value, allocates:\n",[36,561,563,566,569,571,573,575,577,580,583,586,589,592,595],{"class":38,"line":562},53,[36,564,565],{"class":42},"final",[36,567,568],{"class":50}," dynamicGreeting ",[36,570,532],{"class":42},[36,572,408],{"class":91},[36,574,537],{"class":50},[36,576,164],{"class":42},[36,578,579],{"class":91}," DateTime",[36,581,582],{"class":50},".",[36,584,585],{"class":133},"now",[36,587,588],{"class":50},"().",[36,590,591],{"class":133},"toString",[36,593,594],{"class":50},"());  ",[36,596,597],{"class":64},"\u002F\u002F can't be const\n",[14,599,601,604],{"id":600},"statefulwidget-lifecycle-the-two-class-design",[19,602,603],{},"StatefulWidget"," Lifecycle — The Two-Class Design",[24,606,607],{"language":26},[28,608,610],{"className":30,"code":609,"language":26,"meta":32,"style":32},"import 'package:flutter\u002Fmaterial.dart';\n\n\u002F\u002F ── Why two classes? ──\n\u002F\u002F StatefulWidget (immutable): configuration. A new instance is created on\n\u002F\u002F   each parent rebuild.\n\u002F\u002F State (mutable, persisted): the mutable state + lifecycle. Flutter REUSES\n\u002F\u002F   the same State across widget rebuilds (matched by type + key).\n\nclass Counter extends StatefulWidget {\n  final int initialCount;  \u002F\u002F configuration — immutable, may change on rebuild\n  const Counter({super.key, this.initialCount = 0});\n\n  @override\n  State\u003CCounter> createState() => _CounterState();\n}\n\nclass _CounterState extends State\u003CCounter> {\n  late int _count;  \u002F\u002F mutable state — persists across parent rebuilds\n\n  \u002F\u002F ── Lifecycle methods (in order) ──\n\n  @override\n  void initState() {\n    super.initState();\n    \u002F\u002F Runs ONCE when the State is created. Access widget.initialCount here.\n    _count = widget.initialCount;\n    \u002F\u002F Start async work, subscribe to streams, etc. HERE (not in build).\n    _startListening();\n  }\n\n  @override\n  void didUpdateWidget(Counter oldWidget) {\n    super.didUpdateWidget(oldWidget);\n    \u002F\u002F Runs when the parent rebuilds with a NEW widget configuration.\n    \u002F\u002F widget.initialCount may have changed.\n    if (widget.initialCount != oldWidget.initialCount) {\n      _count = widget.initialCount;  \u002F\u002F react to config changes\n    }\n  }\n\n  @override\n  void dispose() {\n    \u002F\u002F Runs ONCE when the State is removed from the tree. Cleanup HERE.\n    _subscription.cancel();  \u002F\u002F cancel stream subscriptions\n    _controller.dispose();  \u002F\u002F dispose TextEditingControllers\n    super.dispose();\n  }\n\n  void _startListening() {\n    _subscription = someStream.listen((event) {\n      if (mounted) setState(() => _lastEvent = event);  \u002F\u002F check mounted before setState\n    });\n  }\n\n  late StreamSubscription _subscription;\n  String? _lastEvent;\n\n  void _increment() {\n    \u002F\u002F setState marks this State as dirty → triggers a rebuild of build().\n    \u002F\u002F The framework schedules a rebuild (not immediate).\n    setState(() {\n      _count++;\n    });\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    \u002F\u002F ── build() MUST be pure ──\n    \u002F\u002F No side effects, no async work, no setState. It can be called many times.\n    \u002F\u002F It reads widget (config) and _count (state), returns a widget tree.\n    return Column(\n      children: [\n        Text('Count: $_count'),\n        if (_lastEvent != null) Text('Event: $_lastEvent'),\n        ElevatedButton(\n          onPressed: _increment,\n          child: const Text('Increment'),\n        ),\n      ],\n    );\n  }\n}\n",[19,611,612,620,624,629,634,639,644,649,653,667,680,706,710,714,743,747,751,769,782,786,791,795,799,810,822,827,837,842,849,853,857,861,875,887,892,897,911,924,929,933,937,941,950,955,969,982,992,996,1000,1009,1025,1052,1057,1061,1066,1077,1089,1094,1104,1110,1116,1125,1136,1141,1146,1151,1156,1169,1175,1181,1187,1197,1206,1226,1260,1268,1279,1298,1304,1309,1314,1319],{"__ignoreMap":32},[36,613,614,616,618],{"class":38,"line":39},[36,615,43],{"class":42},[36,617,47],{"class":46},[36,619,51],{"class":50},[36,621,622],{"class":38,"line":54},[36,623,58],{"emptyLinePlaceholder":57},[36,625,626],{"class":38,"line":61},[36,627,628],{"class":64},"\u002F\u002F ── Why two classes? ──\n",[36,630,631],{"class":38,"line":68},[36,632,633],{"class":64},"\u002F\u002F StatefulWidget (immutable): configuration. A new instance is created on\n",[36,635,636],{"class":38,"line":74},[36,637,638],{"class":64},"\u002F\u002F   each parent rebuild.\n",[36,640,641],{"class":38,"line":79},[36,642,643],{"class":64},"\u002F\u002F State (mutable, persisted): the mutable state + lifecycle. Flutter REUSES\n",[36,645,646],{"class":38,"line":85},[36,647,648],{"class":64},"\u002F\u002F   the same State across widget rebuilds (matched by type + key).\n",[36,650,651],{"class":38,"line":104},[36,652,58],{"emptyLinePlaceholder":57},[36,654,655,657,660,662,665],{"class":38,"line":121},[36,656,88],{"class":42},[36,658,659],{"class":91}," Counter",[36,661,95],{"class":42},[36,663,664],{"class":91}," StatefulWidget",[36,666,101],{"class":50},[36,668,669,671,674,677],{"class":38,"line":127},[36,670,420],{"class":42},[36,672,673],{"class":91}," int",[36,675,676],{"class":50}," initialCount;  ",[36,678,679],{"class":64},"\u002F\u002F configuration — immutable, may change on rebuild\n",[36,681,682,684,686,688,690,692,695,698,700,703],{"class":38,"line":146},[36,683,107],{"class":42},[36,685,659],{"class":91},[36,687,112],{"class":50},[36,689,115],{"class":91},[36,691,440],{"class":50},[36,693,694],{"class":91},"this",[36,696,697],{"class":50},".initialCount ",[36,699,532],{"class":42},[36,701,702],{"class":91}," 0",[36,704,705],{"class":50},"});\n",[36,707,708],{"class":38,"line":158},[36,709,58],{"emptyLinePlaceholder":57},[36,711,712],{"class":38,"line":170},[36,713,124],{"class":42},[36,715,716,719,722,725,728,731,734,737,740],{"class":38,"line":187},[36,717,718],{"class":91},"  State",[36,720,721],{"class":50},"\u003C",[36,723,724],{"class":91},"Counter",[36,726,727],{"class":50},"> ",[36,729,730],{"class":133},"createState",[36,732,733],{"class":50},"() ",[36,735,736],{"class":42},"=>",[36,738,739],{"class":91}," _CounterState",[36,741,742],{"class":50},"();\n",[36,744,745],{"class":38,"line":202},[36,746,239],{"class":50},[36,748,749],{"class":38,"line":218},[36,750,58],{"emptyLinePlaceholder":57},[36,752,753,755,757,759,762,764,766],{"class":38,"line":224},[36,754,88],{"class":42},[36,756,739],{"class":91},[36,758,95],{"class":42},[36,760,761],{"class":91}," State",[36,763,721],{"class":50},[36,765,724],{"class":91},[36,767,768],{"class":50},"> {\n",[36,770,771,774,776,779],{"class":38,"line":230},[36,772,773],{"class":42},"  late",[36,775,673],{"class":91},[36,777,778],{"class":50}," _count;  ",[36,780,781],{"class":64},"\u002F\u002F mutable state — persists across parent rebuilds\n",[36,783,784],{"class":38,"line":236},[36,785,58],{"emptyLinePlaceholder":57},[36,787,788],{"class":38,"line":242},[36,789,790],{"class":64},"  \u002F\u002F ── Lifecycle methods (in order) ──\n",[36,792,793],{"class":38,"line":247},[36,794,58],{"emptyLinePlaceholder":57},[36,796,797],{"class":38,"line":253},[36,798,124],{"class":42},[36,800,801,804,807],{"class":38,"line":267},[36,802,803],{"class":42},"  void",[36,805,806],{"class":133}," initState",[36,808,809],{"class":50},"() {\n",[36,811,812,815,817,820],{"class":38,"line":280},[36,813,814],{"class":91},"    super",[36,816,582],{"class":50},[36,818,819],{"class":133},"initState",[36,821,742],{"class":50},[36,823,824],{"class":38,"line":285},[36,825,826],{"class":64},"    \u002F\u002F Runs ONCE when the State is created. Access widget.initialCount here.\n",[36,828,829,832,834],{"class":38,"line":298},[36,830,831],{"class":50},"    _count ",[36,833,532],{"class":42},[36,835,836],{"class":50}," widget.initialCount;\n",[36,838,839],{"class":38,"line":307},[36,840,841],{"class":64},"    \u002F\u002F Start async work, subscribe to streams, etc. HERE (not in build).\n",[36,843,844,847],{"class":38,"line":319},[36,845,846],{"class":133},"    _startListening",[36,848,742],{"class":50},[36,850,851],{"class":38,"line":333},[36,852,233],{"class":50},[36,854,855],{"class":38,"line":347},[36,856,58],{"emptyLinePlaceholder":57},[36,858,859],{"class":38,"line":360},[36,860,124],{"class":42},[36,862,863,865,868,870,872],{"class":38,"line":365},[36,864,803],{"class":42},[36,866,867],{"class":133}," didUpdateWidget",[36,869,137],{"class":50},[36,871,724],{"class":91},[36,873,874],{"class":50}," oldWidget) {\n",[36,876,877,879,881,884],{"class":38,"line":370},[36,878,814],{"class":91},[36,880,582],{"class":50},[36,882,883],{"class":133},"didUpdateWidget",[36,885,886],{"class":50},"(oldWidget);\n",[36,888,889],{"class":38,"line":375},[36,890,891],{"class":64},"    \u002F\u002F Runs when the parent rebuilds with a NEW widget configuration.\n",[36,893,894],{"class":38,"line":380},[36,895,896],{"class":64},"    \u002F\u002F widget.initialCount may have changed.\n",[36,898,899,902,905,908],{"class":38,"line":385},[36,900,901],{"class":42},"    if",[36,903,904],{"class":50}," (widget.initialCount ",[36,906,907],{"class":42},"!=",[36,909,910],{"class":50}," oldWidget.initialCount) {\n",[36,912,913,916,918,921],{"class":38,"line":391},[36,914,915],{"class":50},"      _count ",[36,917,532],{"class":42},[36,919,920],{"class":50}," widget.initialCount;  ",[36,922,923],{"class":64},"\u002F\u002F react to config changes\n",[36,925,926],{"class":38,"line":397},[36,927,928],{"class":50},"    }\n",[36,930,931],{"class":38,"line":403},[36,932,233],{"class":50},[36,934,935],{"class":38,"line":417},[36,936,58],{"emptyLinePlaceholder":57},[36,938,939],{"class":38,"line":429},[36,940,124],{"class":42},[36,942,943,945,948],{"class":38,"line":455},[36,944,803],{"class":42},[36,946,947],{"class":133}," dispose",[36,949,809],{"class":50},[36,951,952],{"class":38,"line":460},[36,953,954],{"class":64},"    \u002F\u002F Runs ONCE when the State is removed from the tree. Cleanup HERE.\n",[36,956,957,960,963,966],{"class":38,"line":465},[36,958,959],{"class":50},"    _subscription.",[36,961,962],{"class":133},"cancel",[36,964,965],{"class":50},"();  ",[36,967,968],{"class":64},"\u002F\u002F cancel stream subscriptions\n",[36,970,971,974,977,979],{"class":38,"line":478},[36,972,973],{"class":50},"    _controller.",[36,975,976],{"class":133},"dispose",[36,978,965],{"class":50},[36,980,981],{"class":64},"\u002F\u002F dispose TextEditingControllers\n",[36,983,984,986,988,990],{"class":38,"line":503},[36,985,814],{"class":91},[36,987,582],{"class":50},[36,989,976],{"class":133},[36,991,742],{"class":50},[36,993,994],{"class":38,"line":508},[36,995,233],{"class":50},[36,997,998],{"class":38,"line":513},[36,999,58],{"emptyLinePlaceholder":57},[36,1001,1002,1004,1007],{"class":38,"line":518},[36,1003,803],{"class":42},[36,1005,1006],{"class":133}," _startListening",[36,1008,809],{"class":50},[36,1010,1011,1014,1016,1019,1022],{"class":38,"line":524},[36,1012,1013],{"class":50},"    _subscription ",[36,1015,532],{"class":42},[36,1017,1018],{"class":50}," someStream.",[36,1020,1021],{"class":133},"listen",[36,1023,1024],{"class":50},"((event) {\n",[36,1026,1027,1030,1033,1036,1039,1041,1044,1046,1049],{"class":38,"line":551},[36,1028,1029],{"class":42},"      if",[36,1031,1032],{"class":50}," (mounted) ",[36,1034,1035],{"class":133},"setState",[36,1037,1038],{"class":50},"(() ",[36,1040,736],{"class":42},[36,1042,1043],{"class":50}," _lastEvent ",[36,1045,532],{"class":42},[36,1047,1048],{"class":50}," event);  ",[36,1050,1051],{"class":64},"\u002F\u002F check mounted before setState\n",[36,1053,1054],{"class":38,"line":556},[36,1055,1056],{"class":50},"    });\n",[36,1058,1059],{"class":38,"line":562},[36,1060,233],{"class":50},[36,1062,1064],{"class":38,"line":1063},54,[36,1065,58],{"emptyLinePlaceholder":57},[36,1067,1069,1071,1074],{"class":38,"line":1068},55,[36,1070,773],{"class":42},[36,1072,1073],{"class":91}," StreamSubscription",[36,1075,1076],{"class":50}," _subscription;\n",[36,1078,1080,1083,1086],{"class":38,"line":1079},56,[36,1081,1082],{"class":91},"  String",[36,1084,1085],{"class":42},"?",[36,1087,1088],{"class":50}," _lastEvent;\n",[36,1090,1092],{"class":38,"line":1091},57,[36,1093,58],{"emptyLinePlaceholder":57},[36,1095,1097,1099,1102],{"class":38,"line":1096},58,[36,1098,803],{"class":42},[36,1100,1101],{"class":133}," _increment",[36,1103,809],{"class":50},[36,1105,1107],{"class":38,"line":1106},59,[36,1108,1109],{"class":64},"    \u002F\u002F setState marks this State as dirty → triggers a rebuild of build().\n",[36,1111,1113],{"class":38,"line":1112},60,[36,1114,1115],{"class":64},"    \u002F\u002F The framework schedules a rebuild (not immediate).\n",[36,1117,1119,1122],{"class":38,"line":1118},61,[36,1120,1121],{"class":133},"    setState",[36,1123,1124],{"class":50},"(() {\n",[36,1126,1128,1131,1134],{"class":38,"line":1127},62,[36,1129,1130],{"class":50},"      _count",[36,1132,1133],{"class":42},"++",[36,1135,51],{"class":50},[36,1137,1139],{"class":38,"line":1138},63,[36,1140,1056],{"class":50},[36,1142,1144],{"class":38,"line":1143},64,[36,1145,233],{"class":50},[36,1147,1149],{"class":38,"line":1148},65,[36,1150,58],{"emptyLinePlaceholder":57},[36,1152,1154],{"class":38,"line":1153},66,[36,1155,124],{"class":42},[36,1157,1159,1161,1163,1165,1167],{"class":38,"line":1158},67,[36,1160,130],{"class":91},[36,1162,134],{"class":133},[36,1164,137],{"class":50},[36,1166,140],{"class":91},[36,1168,143],{"class":50},[36,1170,1172],{"class":38,"line":1171},68,[36,1173,1174],{"class":64},"    \u002F\u002F ── build() MUST be pure ──\n",[36,1176,1178],{"class":38,"line":1177},69,[36,1179,1180],{"class":64},"    \u002F\u002F No side effects, no async work, no setState. It can be called many times.\n",[36,1182,1184],{"class":38,"line":1183},70,[36,1185,1186],{"class":64},"    \u002F\u002F It reads widget (config) and _count (state), returns a widget tree.\n",[36,1188,1190,1192,1195],{"class":38,"line":1189},71,[36,1191,149],{"class":42},[36,1193,1194],{"class":91}," Column",[36,1196,155],{"class":50},[36,1198,1200,1202,1204],{"class":38,"line":1199},72,[36,1201,161],{"class":50},[36,1203,164],{"class":42},[36,1205,167],{"class":50},[36,1207,1209,1211,1213,1216,1218,1221,1223],{"class":38,"line":1208},73,[36,1210,173],{"class":91},[36,1212,137],{"class":50},[36,1214,1215],{"class":46},"'Count: ",[36,1217,491],{"class":46},[36,1219,1220],{"class":91},"_count",[36,1222,497],{"class":46},[36,1224,1225],{"class":50},"),\n",[36,1227,1229,1232,1235,1237,1240,1243,1246,1248,1251,1253,1256,1258],{"class":38,"line":1228},74,[36,1230,1231],{"class":42},"        if",[36,1233,1234],{"class":50}," (_lastEvent ",[36,1236,907],{"class":42},[36,1238,1239],{"class":91}," null",[36,1241,1242],{"class":50},") ",[36,1244,1245],{"class":91},"Text",[36,1247,137],{"class":50},[36,1249,1250],{"class":46},"'Event: ",[36,1252,491],{"class":46},[36,1254,1255],{"class":91},"_lastEvent",[36,1257,497],{"class":46},[36,1259,1225],{"class":50},[36,1261,1263,1266],{"class":38,"line":1262},75,[36,1264,1265],{"class":91},"        ElevatedButton",[36,1267,155],{"class":50},[36,1269,1271,1274,1276],{"class":38,"line":1270},76,[36,1272,1273],{"class":50},"          onPressed",[36,1275,164],{"class":42},[36,1277,1278],{"class":50}," _increment,\n",[36,1280,1282,1285,1287,1289,1291,1293,1296],{"class":38,"line":1281},77,[36,1283,1284],{"class":50},"          child",[36,1286,164],{"class":42},[36,1288,314],{"class":42},[36,1290,483],{"class":91},[36,1292,137],{"class":50},[36,1294,1295],{"class":46},"'Increment'",[36,1297,1225],{"class":50},[36,1299,1301],{"class":38,"line":1300},78,[36,1302,1303],{"class":50},"        ),\n",[36,1305,1307],{"class":38,"line":1306},79,[36,1308,221],{"class":50},[36,1310,1312],{"class":38,"line":1311},80,[36,1313,227],{"class":50},[36,1315,1317],{"class":38,"line":1316},81,[36,1318,233],{"class":50},[36,1320,1322],{"class":38,"line":1321},82,[36,1323,239],{"class":50},[14,1325,1327,1330],{"id":1326},"build-purity-the-side-effect-trap",[19,1328,1329],{},"build()"," Purity — The Side-Effect Trap",[24,1332,1333],{"language":26},[28,1334,1336],{"className":30,"code":1335,"language":26,"meta":32,"style":32},"import 'package:flutter\u002Fmaterial.dart';\n\n\u002F\u002F ❌ Anti-pattern: side effects in build() — infinite loop or crash.\nclass BadWidget extends StatefulWidget {\n  const BadWidget({super.key});\n  @override\n  State\u003CBadWidget> createState() => _BadWidgetState();\n}\n\nclass _BadWidgetState extends State\u003CBadWidget> {\n  String? _data;\n\n  @override\n  Widget build(BuildContext context) {\n    \u002F\u002F Side effect in build: starts a fetch on every rebuild.\n    fetchData().then((data) {\n      setState(() => _data = data);  \u002F\u002F ← triggers rebuild → fetch again → loop!\n    });\n    return Text(_data ?? 'Loading...');\n  }\n}\n\n\u002F\u002F ✓ Correct: start async work in initState, check mounted before setState.\nclass GoodWidget extends StatefulWidget {\n  const GoodWidget({super.key});\n  @override\n  State\u003CGoodWidget> createState() => _GoodWidgetState();\n}\n\nclass _GoodWidgetState extends State\u003CGoodWidget> {\n  String? _data;\n\n  @override\n  void initState() {\n    super.initState();\n    _loadData();  \u002F\u002F runs once\n  }\n\n  Future\u003Cvoid> _loadData() async {\n    final data = await fetchData();\n    if (mounted) {  \u002F\u002F ← the widget may have been disposed during the await\n      setState(() => _data = data);\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Text(_data ?? 'Loading...');  \u002F\u002F pure — reads state, returns tree\n  }\n}\n\nFuture\u003CString> fetchData() async {\n  await Future.delayed(Duration(seconds: 1));\n  return 'Hello';\n}\n",[19,1337,1338,1346,1350,1355,1368,1380,1384,1406,1410,1414,1430,1439,1443,1447,1459,1464,1477,1497,1501,1518,1522,1526,1530,1535,1548,1560,1564,1586,1590,1594,1610,1618,1622,1626,1634,1644,1654,1658,1662,1684,1702,1712,1727,1731,1735,1739,1743,1755,1772,1776,1780,1784,1805,1834,1844],{"__ignoreMap":32},[36,1339,1340,1342,1344],{"class":38,"line":39},[36,1341,43],{"class":42},[36,1343,47],{"class":46},[36,1345,51],{"class":50},[36,1347,1348],{"class":38,"line":54},[36,1349,58],{"emptyLinePlaceholder":57},[36,1351,1352],{"class":38,"line":61},[36,1353,1354],{"class":64},"\u002F\u002F ❌ Anti-pattern: side effects in build() — infinite loop or crash.\n",[36,1356,1357,1359,1362,1364,1366],{"class":38,"line":68},[36,1358,88],{"class":42},[36,1360,1361],{"class":91}," BadWidget",[36,1363,95],{"class":42},[36,1365,664],{"class":91},[36,1367,101],{"class":50},[36,1369,1370,1372,1374,1376,1378],{"class":38,"line":74},[36,1371,107],{"class":42},[36,1373,1361],{"class":91},[36,1375,112],{"class":50},[36,1377,115],{"class":91},[36,1379,118],{"class":50},[36,1381,1382],{"class":38,"line":79},[36,1383,124],{"class":42},[36,1385,1386,1388,1390,1393,1395,1397,1399,1401,1404],{"class":38,"line":85},[36,1387,718],{"class":91},[36,1389,721],{"class":50},[36,1391,1392],{"class":91},"BadWidget",[36,1394,727],{"class":50},[36,1396,730],{"class":133},[36,1398,733],{"class":50},[36,1400,736],{"class":42},[36,1402,1403],{"class":91}," _BadWidgetState",[36,1405,742],{"class":50},[36,1407,1408],{"class":38,"line":104},[36,1409,239],{"class":50},[36,1411,1412],{"class":38,"line":121},[36,1413,58],{"emptyLinePlaceholder":57},[36,1415,1416,1418,1420,1422,1424,1426,1428],{"class":38,"line":127},[36,1417,88],{"class":42},[36,1419,1403],{"class":91},[36,1421,95],{"class":42},[36,1423,761],{"class":91},[36,1425,721],{"class":50},[36,1427,1392],{"class":91},[36,1429,768],{"class":50},[36,1431,1432,1434,1436],{"class":38,"line":146},[36,1433,1082],{"class":91},[36,1435,1085],{"class":42},[36,1437,1438],{"class":50}," _data;\n",[36,1440,1441],{"class":38,"line":158},[36,1442,58],{"emptyLinePlaceholder":57},[36,1444,1445],{"class":38,"line":170},[36,1446,124],{"class":42},[36,1448,1449,1451,1453,1455,1457],{"class":38,"line":187},[36,1450,130],{"class":91},[36,1452,134],{"class":133},[36,1454,137],{"class":50},[36,1456,140],{"class":91},[36,1458,143],{"class":50},[36,1460,1461],{"class":38,"line":202},[36,1462,1463],{"class":64},"    \u002F\u002F Side effect in build: starts a fetch on every rebuild.\n",[36,1465,1466,1469,1471,1474],{"class":38,"line":218},[36,1467,1468],{"class":133},"    fetchData",[36,1470,588],{"class":50},[36,1472,1473],{"class":133},"then",[36,1475,1476],{"class":50},"((data) {\n",[36,1478,1479,1482,1484,1486,1489,1491,1494],{"class":38,"line":224},[36,1480,1481],{"class":133},"      setState",[36,1483,1038],{"class":50},[36,1485,736],{"class":42},[36,1487,1488],{"class":50}," _data ",[36,1490,532],{"class":42},[36,1492,1493],{"class":50}," data);  ",[36,1495,1496],{"class":64},"\u002F\u002F ← triggers rebuild → fetch again → loop!\n",[36,1498,1499],{"class":38,"line":230},[36,1500,1056],{"class":50},[36,1502,1503,1505,1507,1510,1513,1516],{"class":38,"line":236},[36,1504,149],{"class":42},[36,1506,483],{"class":91},[36,1508,1509],{"class":50},"(_data ",[36,1511,1512],{"class":42},"??",[36,1514,1515],{"class":46}," 'Loading...'",[36,1517,500],{"class":50},[36,1519,1520],{"class":38,"line":242},[36,1521,233],{"class":50},[36,1523,1524],{"class":38,"line":247},[36,1525,239],{"class":50},[36,1527,1528],{"class":38,"line":253},[36,1529,58],{"emptyLinePlaceholder":57},[36,1531,1532],{"class":38,"line":267},[36,1533,1534],{"class":64},"\u002F\u002F ✓ Correct: start async work in initState, check mounted before setState.\n",[36,1536,1537,1539,1542,1544,1546],{"class":38,"line":280},[36,1538,88],{"class":42},[36,1540,1541],{"class":91}," GoodWidget",[36,1543,95],{"class":42},[36,1545,664],{"class":91},[36,1547,101],{"class":50},[36,1549,1550,1552,1554,1556,1558],{"class":38,"line":285},[36,1551,107],{"class":42},[36,1553,1541],{"class":91},[36,1555,112],{"class":50},[36,1557,115],{"class":91},[36,1559,118],{"class":50},[36,1561,1562],{"class":38,"line":298},[36,1563,124],{"class":42},[36,1565,1566,1568,1570,1573,1575,1577,1579,1581,1584],{"class":38,"line":307},[36,1567,718],{"class":91},[36,1569,721],{"class":50},[36,1571,1572],{"class":91},"GoodWidget",[36,1574,727],{"class":50},[36,1576,730],{"class":133},[36,1578,733],{"class":50},[36,1580,736],{"class":42},[36,1582,1583],{"class":91}," _GoodWidgetState",[36,1585,742],{"class":50},[36,1587,1588],{"class":38,"line":319},[36,1589,239],{"class":50},[36,1591,1592],{"class":38,"line":333},[36,1593,58],{"emptyLinePlaceholder":57},[36,1595,1596,1598,1600,1602,1604,1606,1608],{"class":38,"line":347},[36,1597,88],{"class":42},[36,1599,1583],{"class":91},[36,1601,95],{"class":42},[36,1603,761],{"class":91},[36,1605,721],{"class":50},[36,1607,1572],{"class":91},[36,1609,768],{"class":50},[36,1611,1612,1614,1616],{"class":38,"line":360},[36,1613,1082],{"class":91},[36,1615,1085],{"class":42},[36,1617,1438],{"class":50},[36,1619,1620],{"class":38,"line":365},[36,1621,58],{"emptyLinePlaceholder":57},[36,1623,1624],{"class":38,"line":370},[36,1625,124],{"class":42},[36,1627,1628,1630,1632],{"class":38,"line":375},[36,1629,803],{"class":42},[36,1631,806],{"class":133},[36,1633,809],{"class":50},[36,1635,1636,1638,1640,1642],{"class":38,"line":380},[36,1637,814],{"class":91},[36,1639,582],{"class":50},[36,1641,819],{"class":133},[36,1643,742],{"class":50},[36,1645,1646,1649,1651],{"class":38,"line":385},[36,1647,1648],{"class":133},"    _loadData",[36,1650,965],{"class":50},[36,1652,1653],{"class":64},"\u002F\u002F runs once\n",[36,1655,1656],{"class":38,"line":391},[36,1657,233],{"class":50},[36,1659,1660],{"class":38,"line":397},[36,1661,58],{"emptyLinePlaceholder":57},[36,1663,1664,1667,1669,1672,1674,1677,1679,1682],{"class":38,"line":403},[36,1665,1666],{"class":91},"  Future",[36,1668,721],{"class":50},[36,1670,1671],{"class":42},"void",[36,1673,727],{"class":50},[36,1675,1676],{"class":133},"_loadData",[36,1678,733],{"class":50},[36,1680,1681],{"class":42},"async",[36,1683,101],{"class":50},[36,1685,1686,1689,1692,1694,1697,1700],{"class":38,"line":417},[36,1687,1688],{"class":42},"    final",[36,1690,1691],{"class":50}," data ",[36,1693,532],{"class":42},[36,1695,1696],{"class":42}," await",[36,1698,1699],{"class":133}," fetchData",[36,1701,742],{"class":50},[36,1703,1704,1706,1709],{"class":38,"line":429},[36,1705,901],{"class":42},[36,1707,1708],{"class":50}," (mounted) {  ",[36,1710,1711],{"class":64},"\u002F\u002F ← the widget may have been disposed during the await\n",[36,1713,1714,1716,1718,1720,1722,1724],{"class":38,"line":455},[36,1715,1481],{"class":133},[36,1717,1038],{"class":50},[36,1719,736],{"class":42},[36,1721,1488],{"class":50},[36,1723,532],{"class":42},[36,1725,1726],{"class":50}," data);\n",[36,1728,1729],{"class":38,"line":460},[36,1730,928],{"class":50},[36,1732,1733],{"class":38,"line":465},[36,1734,233],{"class":50},[36,1736,1737],{"class":38,"line":478},[36,1738,58],{"emptyLinePlaceholder":57},[36,1740,1741],{"class":38,"line":503},[36,1742,124],{"class":42},[36,1744,1745,1747,1749,1751,1753],{"class":38,"line":508},[36,1746,130],{"class":91},[36,1748,134],{"class":133},[36,1750,137],{"class":50},[36,1752,140],{"class":91},[36,1754,143],{"class":50},[36,1756,1757,1759,1761,1763,1765,1767,1769],{"class":38,"line":513},[36,1758,149],{"class":42},[36,1760,483],{"class":91},[36,1762,1509],{"class":50},[36,1764,1512],{"class":42},[36,1766,1515],{"class":46},[36,1768,545],{"class":50},[36,1770,1771],{"class":64},"\u002F\u002F pure — reads state, returns tree\n",[36,1773,1774],{"class":38,"line":518},[36,1775,233],{"class":50},[36,1777,1778],{"class":38,"line":524},[36,1779,239],{"class":50},[36,1781,1782],{"class":38,"line":551},[36,1783,58],{"emptyLinePlaceholder":57},[36,1785,1786,1789,1791,1794,1796,1799,1801,1803],{"class":38,"line":556},[36,1787,1788],{"class":91},"Future",[36,1790,721],{"class":50},[36,1792,1793],{"class":91},"String",[36,1795,727],{"class":50},[36,1797,1798],{"class":133},"fetchData",[36,1800,733],{"class":50},[36,1802,1681],{"class":42},[36,1804,101],{"class":50},[36,1806,1807,1810,1813,1815,1818,1820,1823,1826,1828,1831],{"class":38,"line":562},[36,1808,1809],{"class":42},"  await",[36,1811,1812],{"class":91}," Future",[36,1814,582],{"class":50},[36,1816,1817],{"class":133},"delayed",[36,1819,137],{"class":50},[36,1821,1822],{"class":91},"Duration",[36,1824,1825],{"class":50},"(seconds",[36,1827,164],{"class":42},[36,1829,1830],{"class":91}," 1",[36,1832,1833],{"class":50},"));\n",[36,1835,1836,1839,1842],{"class":38,"line":1063},[36,1837,1838],{"class":42},"  return",[36,1840,1841],{"class":46}," 'Hello'",[36,1843,51],{"class":50},[36,1845,1846],{"class":38,"line":1068},[36,1847,239],{"class":50},[14,1849,1851,1853,1854,1857],{"id":1850},"buildcontext-the-mounted-check-after-await",[19,1852,140],{}," — The ",[19,1855,1856],{},"mounted"," Check After Await",[24,1859,1860],{"language":26},[28,1861,1863],{"className":30,"code":1862,"language":26,"meta":32,"style":32},"import 'package:flutter\u002Fmaterial.dart';\n\n\u002F\u002F After `await`, the widget may have been removed from the tree (navigated away,\n\u002F\u002F parent rebuilt without this child, etc.). Using `context` or `setState`\n\u002F\u002F after dispose throws (\"setState\u002Fmounted called after dispose()\").\n\nclass DetailPage extends StatefulWidget {\n  const DetailPage({super.key});\n  @override\n  State\u003CDetailPage> createState() => _DetailPageState();\n}\n\nclass _DetailPageState extends State\u003CDetailPage> {\n  User? _user;\n\n  @override\n  void initState() {\n    super.initState();\n    _loadUser();\n  }\n\n  Future\u003Cvoid> _loadUser() async {\n    _user = await fetchUser();  \u002F\u002F may take seconds\n\n    \u002F\u002F ❌ Anti-pattern: using context or setState without checking mounted.\n    \u002F\u002F if (_user != null) setState(() {});  \u002F\u002F ✗ may throw if disposed\n\n    \u002F\u002F ✓ Correct: check `mounted` (State property — true if still in the tree).\n    if (!mounted) return;  \u002F\u002F widget was disposed during await — abort\n    setState(() {});  \u002F\u002F safe — widget is still mounted\n  }\n\n  Future\u003Cvoid> _refresh() async {\n    _user = await fetchUser();\n    \u002F\u002F Or use `context.mounted` (BuildContext property, Dart 3.7+):\n    if (!context.mounted) return;\n    setState(() {});  \u002F\u002F safe\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    \u002F\u002F ❌ Anti-pattern: using context across an async gap inside build.\n    \u002F\u002F build() should be sync. But if you have a callback:\n    return ElevatedButton(\n      onPressed: () async {\n        await Navigator.push(context, MaterialPageRoute(\n          builder: (_) => const EditPage(),\n        ));\n        \u002F\u002F After await: context may be unmounted if the user navigated away.\n        if (!context.mounted) return;\n        _refresh();  \u002F\u002F safe to use context now\n      },\n      child: const Text('Edit'),\n    );\n  }\n}\n\nFuture\u003CUser> fetchUser() async => User('Alice');\nclass User { final String name; User(this.name); }\nclass EditPage extends StatelessWidget {\n  const EditPage({super.key});\n  @override\n  Widget build(BuildContext context) => const Scaffold(body: Text('Edit'));\n}\n",[19,1864,1865,1873,1877,1882,1887,1892,1896,1909,1921,1925,1947,1951,1955,1971,1981,1985,1989,1997,2007,2014,2018,2022,2041,2058,2062,2067,2075,2079,2084,2106,2116,2120,2124,2143,2155,2160,2175,2184,2188,2192,2196,2208,2213,2218,2227,2241,2262,2282,2287,2292,2306,2316,2321,2339,2343,2347,2351,2355,2386,2411,2423,2435,2439,2472],{"__ignoreMap":32},[36,1866,1867,1869,1871],{"class":38,"line":39},[36,1868,43],{"class":42},[36,1870,47],{"class":46},[36,1872,51],{"class":50},[36,1874,1875],{"class":38,"line":54},[36,1876,58],{"emptyLinePlaceholder":57},[36,1878,1879],{"class":38,"line":61},[36,1880,1881],{"class":64},"\u002F\u002F After `await`, the widget may have been removed from the tree (navigated away,\n",[36,1883,1884],{"class":38,"line":68},[36,1885,1886],{"class":64},"\u002F\u002F parent rebuilt without this child, etc.). Using `context` or `setState`\n",[36,1888,1889],{"class":38,"line":74},[36,1890,1891],{"class":64},"\u002F\u002F after dispose throws (\"setState\u002Fmounted called after dispose()\").\n",[36,1893,1894],{"class":38,"line":79},[36,1895,58],{"emptyLinePlaceholder":57},[36,1897,1898,1900,1903,1905,1907],{"class":38,"line":85},[36,1899,88],{"class":42},[36,1901,1902],{"class":91}," DetailPage",[36,1904,95],{"class":42},[36,1906,664],{"class":91},[36,1908,101],{"class":50},[36,1910,1911,1913,1915,1917,1919],{"class":38,"line":104},[36,1912,107],{"class":42},[36,1914,1902],{"class":91},[36,1916,112],{"class":50},[36,1918,115],{"class":91},[36,1920,118],{"class":50},[36,1922,1923],{"class":38,"line":121},[36,1924,124],{"class":42},[36,1926,1927,1929,1931,1934,1936,1938,1940,1942,1945],{"class":38,"line":127},[36,1928,718],{"class":91},[36,1930,721],{"class":50},[36,1932,1933],{"class":91},"DetailPage",[36,1935,727],{"class":50},[36,1937,730],{"class":133},[36,1939,733],{"class":50},[36,1941,736],{"class":42},[36,1943,1944],{"class":91}," _DetailPageState",[36,1946,742],{"class":50},[36,1948,1949],{"class":38,"line":146},[36,1950,239],{"class":50},[36,1952,1953],{"class":38,"line":158},[36,1954,58],{"emptyLinePlaceholder":57},[36,1956,1957,1959,1961,1963,1965,1967,1969],{"class":38,"line":170},[36,1958,88],{"class":42},[36,1960,1944],{"class":91},[36,1962,95],{"class":42},[36,1964,761],{"class":91},[36,1966,721],{"class":50},[36,1968,1933],{"class":91},[36,1970,768],{"class":50},[36,1972,1973,1976,1978],{"class":38,"line":187},[36,1974,1975],{"class":91},"  User",[36,1977,1085],{"class":42},[36,1979,1980],{"class":50}," _user;\n",[36,1982,1983],{"class":38,"line":202},[36,1984,58],{"emptyLinePlaceholder":57},[36,1986,1987],{"class":38,"line":218},[36,1988,124],{"class":42},[36,1990,1991,1993,1995],{"class":38,"line":224},[36,1992,803],{"class":42},[36,1994,806],{"class":133},[36,1996,809],{"class":50},[36,1998,1999,2001,2003,2005],{"class":38,"line":230},[36,2000,814],{"class":91},[36,2002,582],{"class":50},[36,2004,819],{"class":133},[36,2006,742],{"class":50},[36,2008,2009,2012],{"class":38,"line":236},[36,2010,2011],{"class":133},"    _loadUser",[36,2013,742],{"class":50},[36,2015,2016],{"class":38,"line":242},[36,2017,233],{"class":50},[36,2019,2020],{"class":38,"line":247},[36,2021,58],{"emptyLinePlaceholder":57},[36,2023,2024,2026,2028,2030,2032,2035,2037,2039],{"class":38,"line":253},[36,2025,1666],{"class":91},[36,2027,721],{"class":50},[36,2029,1671],{"class":42},[36,2031,727],{"class":50},[36,2033,2034],{"class":133},"_loadUser",[36,2036,733],{"class":50},[36,2038,1681],{"class":42},[36,2040,101],{"class":50},[36,2042,2043,2046,2048,2050,2053,2055],{"class":38,"line":267},[36,2044,2045],{"class":50},"    _user ",[36,2047,532],{"class":42},[36,2049,1696],{"class":42},[36,2051,2052],{"class":133}," fetchUser",[36,2054,965],{"class":50},[36,2056,2057],{"class":64},"\u002F\u002F may take seconds\n",[36,2059,2060],{"class":38,"line":280},[36,2061,58],{"emptyLinePlaceholder":57},[36,2063,2064],{"class":38,"line":285},[36,2065,2066],{"class":64},"    \u002F\u002F ❌ Anti-pattern: using context or setState without checking mounted.\n",[36,2068,2069,2072],{"class":38,"line":298},[36,2070,2071],{"class":64},"    \u002F\u002F if (_user != null) setState(() {});",[36,2073,2074],{"class":64},"  \u002F\u002F ✗ may throw if disposed\n",[36,2076,2077],{"class":38,"line":307},[36,2078,58],{"emptyLinePlaceholder":57},[36,2080,2081],{"class":38,"line":319},[36,2082,2083],{"class":64},"    \u002F\u002F ✓ Correct: check `mounted` (State property — true if still in the tree).\n",[36,2085,2086,2088,2091,2094,2097,2100,2103],{"class":38,"line":333},[36,2087,901],{"class":42},[36,2089,2090],{"class":50}," (",[36,2092,2093],{"class":42},"!",[36,2095,2096],{"class":50},"mounted) ",[36,2098,2099],{"class":42},"return",[36,2101,2102],{"class":50},";  ",[36,2104,2105],{"class":64},"\u002F\u002F widget was disposed during await — abort\n",[36,2107,2108,2110,2113],{"class":38,"line":347},[36,2109,1121],{"class":133},[36,2111,2112],{"class":50},"(() {});  ",[36,2114,2115],{"class":64},"\u002F\u002F safe — widget is still mounted\n",[36,2117,2118],{"class":38,"line":360},[36,2119,233],{"class":50},[36,2121,2122],{"class":38,"line":365},[36,2123,58],{"emptyLinePlaceholder":57},[36,2125,2126,2128,2130,2132,2134,2137,2139,2141],{"class":38,"line":370},[36,2127,1666],{"class":91},[36,2129,721],{"class":50},[36,2131,1671],{"class":42},[36,2133,727],{"class":50},[36,2135,2136],{"class":133},"_refresh",[36,2138,733],{"class":50},[36,2140,1681],{"class":42},[36,2142,101],{"class":50},[36,2144,2145,2147,2149,2151,2153],{"class":38,"line":375},[36,2146,2045],{"class":50},[36,2148,532],{"class":42},[36,2150,1696],{"class":42},[36,2152,2052],{"class":133},[36,2154,742],{"class":50},[36,2156,2157],{"class":38,"line":380},[36,2158,2159],{"class":64},"    \u002F\u002F Or use `context.mounted` (BuildContext property, Dart 3.7+):\n",[36,2161,2162,2164,2166,2168,2171,2173],{"class":38,"line":385},[36,2163,901],{"class":42},[36,2165,2090],{"class":50},[36,2167,2093],{"class":42},[36,2169,2170],{"class":50},"context.mounted) ",[36,2172,2099],{"class":42},[36,2174,51],{"class":50},[36,2176,2177,2179,2181],{"class":38,"line":391},[36,2178,1121],{"class":133},[36,2180,2112],{"class":50},[36,2182,2183],{"class":64},"\u002F\u002F safe\n",[36,2185,2186],{"class":38,"line":397},[36,2187,233],{"class":50},[36,2189,2190],{"class":38,"line":403},[36,2191,58],{"emptyLinePlaceholder":57},[36,2193,2194],{"class":38,"line":417},[36,2195,124],{"class":42},[36,2197,2198,2200,2202,2204,2206],{"class":38,"line":429},[36,2199,130],{"class":91},[36,2201,134],{"class":133},[36,2203,137],{"class":50},[36,2205,140],{"class":91},[36,2207,143],{"class":50},[36,2209,2210],{"class":38,"line":455},[36,2211,2212],{"class":64},"    \u002F\u002F ❌ Anti-pattern: using context across an async gap inside build.\n",[36,2214,2215],{"class":38,"line":460},[36,2216,2217],{"class":64},"    \u002F\u002F build() should be sync. But if you have a callback:\n",[36,2219,2220,2222,2225],{"class":38,"line":465},[36,2221,149],{"class":42},[36,2223,2224],{"class":91}," ElevatedButton",[36,2226,155],{"class":50},[36,2228,2229,2232,2234,2237,2239],{"class":38,"line":478},[36,2230,2231],{"class":50},"      onPressed",[36,2233,164],{"class":42},[36,2235,2236],{"class":50}," () ",[36,2238,1681],{"class":42},[36,2240,101],{"class":50},[36,2242,2243,2246,2249,2251,2254,2257,2260],{"class":38,"line":503},[36,2244,2245],{"class":42},"        await",[36,2247,2248],{"class":91}," Navigator",[36,2250,582],{"class":50},[36,2252,2253],{"class":133},"push",[36,2255,2256],{"class":50},"(context, ",[36,2258,2259],{"class":91},"MaterialPageRoute",[36,2261,155],{"class":50},[36,2263,2264,2267,2269,2272,2274,2276,2279],{"class":38,"line":508},[36,2265,2266],{"class":50},"          builder",[36,2268,164],{"class":42},[36,2270,2271],{"class":50}," (_) ",[36,2273,736],{"class":42},[36,2275,314],{"class":42},[36,2277,2278],{"class":91}," EditPage",[36,2280,2281],{"class":50},"(),\n",[36,2283,2284],{"class":38,"line":513},[36,2285,2286],{"class":50},"        ));\n",[36,2288,2289],{"class":38,"line":518},[36,2290,2291],{"class":64},"        \u002F\u002F After await: context may be unmounted if the user navigated away.\n",[36,2293,2294,2296,2298,2300,2302,2304],{"class":38,"line":524},[36,2295,1231],{"class":42},[36,2297,2090],{"class":50},[36,2299,2093],{"class":42},[36,2301,2170],{"class":50},[36,2303,2099],{"class":42},[36,2305,51],{"class":50},[36,2307,2308,2311,2313],{"class":38,"line":551},[36,2309,2310],{"class":133},"        _refresh",[36,2312,965],{"class":50},[36,2314,2315],{"class":64},"\u002F\u002F safe to use context now\n",[36,2317,2318],{"class":38,"line":556},[36,2319,2320],{"class":50},"      },\n",[36,2322,2323,2326,2328,2330,2332,2334,2337],{"class":38,"line":562},[36,2324,2325],{"class":50},"      child",[36,2327,164],{"class":42},[36,2329,314],{"class":42},[36,2331,483],{"class":91},[36,2333,137],{"class":50},[36,2335,2336],{"class":46},"'Edit'",[36,2338,1225],{"class":50},[36,2340,2341],{"class":38,"line":1063},[36,2342,227],{"class":50},[36,2344,2345],{"class":38,"line":1068},[36,2346,233],{"class":50},[36,2348,2349],{"class":38,"line":1079},[36,2350,239],{"class":50},[36,2352,2353],{"class":38,"line":1091},[36,2354,58],{"emptyLinePlaceholder":57},[36,2356,2357,2359,2361,2364,2366,2369,2371,2373,2376,2379,2381,2384],{"class":38,"line":1096},[36,2358,1788],{"class":91},[36,2360,721],{"class":50},[36,2362,2363],{"class":91},"User",[36,2365,727],{"class":50},[36,2367,2368],{"class":133},"fetchUser",[36,2370,733],{"class":50},[36,2372,1681],{"class":42},[36,2374,2375],{"class":42}," =>",[36,2377,2378],{"class":91}," User",[36,2380,137],{"class":50},[36,2382,2383],{"class":46},"'Alice'",[36,2385,500],{"class":50},[36,2387,2388,2390,2392,2395,2397,2399,2402,2404,2406,2408],{"class":38,"line":1106},[36,2389,88],{"class":42},[36,2391,2378],{"class":91},[36,2393,2394],{"class":50}," { ",[36,2396,565],{"class":42},[36,2398,423],{"class":91},[36,2400,2401],{"class":50}," name; ",[36,2403,2363],{"class":91},[36,2405,137],{"class":50},[36,2407,694],{"class":91},[36,2409,2410],{"class":50},".name); }\n",[36,2412,2413,2415,2417,2419,2421],{"class":38,"line":1112},[36,2414,88],{"class":42},[36,2416,2278],{"class":91},[36,2418,95],{"class":42},[36,2420,98],{"class":91},[36,2422,101],{"class":50},[36,2424,2425,2427,2429,2431,2433],{"class":38,"line":1118},[36,2426,107],{"class":42},[36,2428,2278],{"class":91},[36,2430,112],{"class":50},[36,2432,115],{"class":91},[36,2434,118],{"class":50},[36,2436,2437],{"class":38,"line":1127},[36,2438,124],{"class":42},[36,2440,2441,2443,2445,2447,2449,2452,2454,2456,2459,2462,2464,2466,2468,2470],{"class":38,"line":1138},[36,2442,130],{"class":91},[36,2444,134],{"class":133},[36,2446,137],{"class":50},[36,2448,140],{"class":91},[36,2450,2451],{"class":50}," context) ",[36,2453,736],{"class":42},[36,2455,314],{"class":42},[36,2457,2458],{"class":91}," Scaffold",[36,2460,2461],{"class":50},"(body",[36,2463,164],{"class":42},[36,2465,483],{"class":91},[36,2467,137],{"class":50},[36,2469,2336],{"class":46},[36,2471,1833],{"class":50},[36,2473,2474],{"class":38,"line":1143},[36,2475,239],{"class":50},[14,2477,2479,2482],{"id":2478},"listviewbuilder-lazy-building-for-long-lists",[19,2480,2481],{},"ListView.builder"," — Lazy Building for Long Lists",[24,2484,2485],{"language":26},[28,2486,2488],{"className":30,"code":2487,"language":26,"meta":32,"style":32},"import 'package:flutter\u002Fmaterial.dart';\n\n\u002F\u002F ❌ Anti-pattern: ListView with all children — builds everything eagerly.\nclass BadListView extends StatelessWidget {\n  final List\u003CString> items;\n  const BadListView({super.key, required this.items});\n\n  @override\n  Widget build(BuildContext context) {\n    return ListView(\n      children: items.map((item) => ListTile(title: Text(item))).toList(),\n    );\n    \u002F\u002F For 10,000 items, this builds 10,000 ListTiles upfront — slow, memory-heavy.\n  }\n}\n\n\u002F\u002F ✓ Correct: ListView.builder — builds only visible items (lazy).\nclass GoodListView extends StatelessWidget {\n  final List\u003CString> items;\n  const GoodListView({super.key, required this.items});\n\n  @override\n  Widget build(BuildContext context) {\n    return ListView.builder(\n      itemCount: items.length,\n      itemBuilder: (context, index) {\n        return ListTile(title: Text(items[index]));\n        \u002F\u002F Only ~10-15 items are built (visible + a few cached). Scrolling builds more.\n      },\n    );\n  }\n}\n\n\u002F\u002F ── Keys for state preservation ──\n\u002F\u002F When items reorder, Flutter matches by type by default — state can jump\n\u002F\u002F to the wrong item. Use ValueKey to preserve state per item identity.\nclass KeyedListView extends StatelessWidget {\n  final List\u003CItem> items;\n  const KeyedListView({super.key, required this.items});\n\n  @override\n  Widget build(BuildContext context) {\n    return ListView.builder(\n      itemCount: items.length,\n      itemBuilder: (context, index) {\n        final item = items[index];\n        return ListTile(\n          key: ValueKey(item.id),  \u002F\u002F ← preserves state if this item reorders\n          title: Text(item.title),\n          leading: Checkbox(\n            value: item.checked,\n            onChanged: (val) => item.checked = val ?? false,\n          ),\n        );\n      },\n    );\n  }\n}\n\nclass Item {\n  final String id;\n  final String title;\n  bool checked;\n  Item(this.id, this.title, {this.checked = false});\n}\n",[19,2489,2490,2498,2502,2507,2520,2534,2553,2557,2561,2573,2581,2616,2620,2625,2629,2633,2637,2642,2655,2667,2685,2689,2693,2705,2718,2728,2738,2754,2759,2763,2767,2771,2775,2779,2784,2789,2794,2807,2820,2838,2842,2846,2858,2870,2878,2886,2899,2907,2923,2935,2947,2957,2985,2990,2995,2999,3003,3007,3011,3015,3024,3033,3042,3050,3078],{"__ignoreMap":32},[36,2491,2492,2494,2496],{"class":38,"line":39},[36,2493,43],{"class":42},[36,2495,47],{"class":46},[36,2497,51],{"class":50},[36,2499,2500],{"class":38,"line":54},[36,2501,58],{"emptyLinePlaceholder":57},[36,2503,2504],{"class":38,"line":61},[36,2505,2506],{"class":64},"\u002F\u002F ❌ Anti-pattern: ListView with all children — builds everything eagerly.\n",[36,2508,2509,2511,2514,2516,2518],{"class":38,"line":68},[36,2510,88],{"class":42},[36,2512,2513],{"class":91}," BadListView",[36,2515,95],{"class":42},[36,2517,98],{"class":91},[36,2519,101],{"class":50},[36,2521,2522,2524,2527,2529,2531],{"class":38,"line":74},[36,2523,420],{"class":42},[36,2525,2526],{"class":91}," List",[36,2528,721],{"class":50},[36,2530,1793],{"class":91},[36,2532,2533],{"class":50},"> items;\n",[36,2535,2536,2538,2540,2542,2544,2546,2548,2550],{"class":38,"line":79},[36,2537,107],{"class":42},[36,2539,2513],{"class":91},[36,2541,112],{"class":50},[36,2543,115],{"class":91},[36,2545,440],{"class":50},[36,2547,443],{"class":42},[36,2549,446],{"class":91},[36,2551,2552],{"class":50},".items});\n",[36,2554,2555],{"class":38,"line":85},[36,2556,58],{"emptyLinePlaceholder":57},[36,2558,2559],{"class":38,"line":104},[36,2560,124],{"class":42},[36,2562,2563,2565,2567,2569,2571],{"class":38,"line":121},[36,2564,130],{"class":91},[36,2566,134],{"class":133},[36,2568,137],{"class":50},[36,2570,140],{"class":91},[36,2572,143],{"class":50},[36,2574,2575,2577,2579],{"class":38,"line":127},[36,2576,149],{"class":42},[36,2578,152],{"class":91},[36,2580,155],{"class":50},[36,2582,2583,2585,2587,2590,2593,2596,2598,2601,2604,2606,2608,2611,2614],{"class":38,"line":146},[36,2584,161],{"class":50},[36,2586,164],{"class":42},[36,2588,2589],{"class":50}," items.",[36,2591,2592],{"class":133},"map",[36,2594,2595],{"class":50},"((item) ",[36,2597,736],{"class":42},[36,2599,2600],{"class":91}," ListTile",[36,2602,2603],{"class":50},"(title",[36,2605,164],{"class":42},[36,2607,483],{"class":91},[36,2609,2610],{"class":50},"(item))).",[36,2612,2613],{"class":133},"toList",[36,2615,2281],{"class":50},[36,2617,2618],{"class":38,"line":158},[36,2619,227],{"class":50},[36,2621,2622],{"class":38,"line":170},[36,2623,2624],{"class":64},"    \u002F\u002F For 10,000 items, this builds 10,000 ListTiles upfront — slow, memory-heavy.\n",[36,2626,2627],{"class":38,"line":187},[36,2628,233],{"class":50},[36,2630,2631],{"class":38,"line":202},[36,2632,239],{"class":50},[36,2634,2635],{"class":38,"line":218},[36,2636,58],{"emptyLinePlaceholder":57},[36,2638,2639],{"class":38,"line":224},[36,2640,2641],{"class":64},"\u002F\u002F ✓ Correct: ListView.builder — builds only visible items (lazy).\n",[36,2643,2644,2646,2649,2651,2653],{"class":38,"line":230},[36,2645,88],{"class":42},[36,2647,2648],{"class":91}," GoodListView",[36,2650,95],{"class":42},[36,2652,98],{"class":91},[36,2654,101],{"class":50},[36,2656,2657,2659,2661,2663,2665],{"class":38,"line":236},[36,2658,420],{"class":42},[36,2660,2526],{"class":91},[36,2662,721],{"class":50},[36,2664,1793],{"class":91},[36,2666,2533],{"class":50},[36,2668,2669,2671,2673,2675,2677,2679,2681,2683],{"class":38,"line":242},[36,2670,107],{"class":42},[36,2672,2648],{"class":91},[36,2674,112],{"class":50},[36,2676,115],{"class":91},[36,2678,440],{"class":50},[36,2680,443],{"class":42},[36,2682,446],{"class":91},[36,2684,2552],{"class":50},[36,2686,2687],{"class":38,"line":247},[36,2688,58],{"emptyLinePlaceholder":57},[36,2690,2691],{"class":38,"line":253},[36,2692,124],{"class":42},[36,2694,2695,2697,2699,2701,2703],{"class":38,"line":267},[36,2696,130],{"class":91},[36,2698,134],{"class":133},[36,2700,137],{"class":50},[36,2702,140],{"class":91},[36,2704,143],{"class":50},[36,2706,2707,2709,2711,2713,2716],{"class":38,"line":280},[36,2708,149],{"class":42},[36,2710,152],{"class":91},[36,2712,582],{"class":50},[36,2714,2715],{"class":133},"builder",[36,2717,155],{"class":50},[36,2719,2720,2723,2725],{"class":38,"line":285},[36,2721,2722],{"class":50},"      itemCount",[36,2724,164],{"class":42},[36,2726,2727],{"class":50}," items.length,\n",[36,2729,2730,2733,2735],{"class":38,"line":298},[36,2731,2732],{"class":50},"      itemBuilder",[36,2734,164],{"class":42},[36,2736,2737],{"class":50}," (context, index) {\n",[36,2739,2740,2743,2745,2747,2749,2751],{"class":38,"line":307},[36,2741,2742],{"class":42},"        return",[36,2744,2600],{"class":91},[36,2746,2603],{"class":50},[36,2748,164],{"class":42},[36,2750,483],{"class":91},[36,2752,2753],{"class":50},"(items[index]));\n",[36,2755,2756],{"class":38,"line":319},[36,2757,2758],{"class":64},"        \u002F\u002F Only ~10-15 items are built (visible + a few cached). Scrolling builds more.\n",[36,2760,2761],{"class":38,"line":333},[36,2762,2320],{"class":50},[36,2764,2765],{"class":38,"line":347},[36,2766,227],{"class":50},[36,2768,2769],{"class":38,"line":360},[36,2770,233],{"class":50},[36,2772,2773],{"class":38,"line":365},[36,2774,239],{"class":50},[36,2776,2777],{"class":38,"line":370},[36,2778,58],{"emptyLinePlaceholder":57},[36,2780,2781],{"class":38,"line":375},[36,2782,2783],{"class":64},"\u002F\u002F ── Keys for state preservation ──\n",[36,2785,2786],{"class":38,"line":380},[36,2787,2788],{"class":64},"\u002F\u002F When items reorder, Flutter matches by type by default — state can jump\n",[36,2790,2791],{"class":38,"line":385},[36,2792,2793],{"class":64},"\u002F\u002F to the wrong item. Use ValueKey to preserve state per item identity.\n",[36,2795,2796,2798,2801,2803,2805],{"class":38,"line":391},[36,2797,88],{"class":42},[36,2799,2800],{"class":91}," KeyedListView",[36,2802,95],{"class":42},[36,2804,98],{"class":91},[36,2806,101],{"class":50},[36,2808,2809,2811,2813,2815,2818],{"class":38,"line":397},[36,2810,420],{"class":42},[36,2812,2526],{"class":91},[36,2814,721],{"class":50},[36,2816,2817],{"class":91},"Item",[36,2819,2533],{"class":50},[36,2821,2822,2824,2826,2828,2830,2832,2834,2836],{"class":38,"line":403},[36,2823,107],{"class":42},[36,2825,2800],{"class":91},[36,2827,112],{"class":50},[36,2829,115],{"class":91},[36,2831,440],{"class":50},[36,2833,443],{"class":42},[36,2835,446],{"class":91},[36,2837,2552],{"class":50},[36,2839,2840],{"class":38,"line":417},[36,2841,58],{"emptyLinePlaceholder":57},[36,2843,2844],{"class":38,"line":429},[36,2845,124],{"class":42},[36,2847,2848,2850,2852,2854,2856],{"class":38,"line":455},[36,2849,130],{"class":91},[36,2851,134],{"class":133},[36,2853,137],{"class":50},[36,2855,140],{"class":91},[36,2857,143],{"class":50},[36,2859,2860,2862,2864,2866,2868],{"class":38,"line":460},[36,2861,149],{"class":42},[36,2863,152],{"class":91},[36,2865,582],{"class":50},[36,2867,2715],{"class":133},[36,2869,155],{"class":50},[36,2871,2872,2874,2876],{"class":38,"line":465},[36,2873,2722],{"class":50},[36,2875,164],{"class":42},[36,2877,2727],{"class":50},[36,2879,2880,2882,2884],{"class":38,"line":478},[36,2881,2732],{"class":50},[36,2883,164],{"class":42},[36,2885,2737],{"class":50},[36,2887,2888,2891,2894,2896],{"class":38,"line":503},[36,2889,2890],{"class":42},"        final",[36,2892,2893],{"class":50}," item ",[36,2895,532],{"class":42},[36,2897,2898],{"class":50}," items[index];\n",[36,2900,2901,2903,2905],{"class":38,"line":508},[36,2902,2742],{"class":42},[36,2904,2600],{"class":91},[36,2906,155],{"class":50},[36,2908,2909,2912,2914,2917,2920],{"class":38,"line":513},[36,2910,2911],{"class":50},"          key",[36,2913,164],{"class":42},[36,2915,2916],{"class":91}," ValueKey",[36,2918,2919],{"class":50},"(item.id),  ",[36,2921,2922],{"class":64},"\u002F\u002F ← preserves state if this item reorders\n",[36,2924,2925,2928,2930,2932],{"class":38,"line":518},[36,2926,2927],{"class":50},"          title",[36,2929,164],{"class":42},[36,2931,483],{"class":91},[36,2933,2934],{"class":50},"(item.title),\n",[36,2936,2937,2940,2942,2945],{"class":38,"line":524},[36,2938,2939],{"class":50},"          leading",[36,2941,164],{"class":42},[36,2943,2944],{"class":91}," Checkbox",[36,2946,155],{"class":50},[36,2948,2949,2952,2954],{"class":38,"line":551},[36,2950,2951],{"class":50},"            value",[36,2953,164],{"class":42},[36,2955,2956],{"class":50}," item.checked,\n",[36,2958,2959,2962,2964,2967,2969,2972,2974,2977,2979,2982],{"class":38,"line":556},[36,2960,2961],{"class":50},"            onChanged",[36,2963,164],{"class":42},[36,2965,2966],{"class":50}," (val) ",[36,2968,736],{"class":42},[36,2970,2971],{"class":50}," item.checked ",[36,2973,532],{"class":42},[36,2975,2976],{"class":50}," val ",[36,2978,1512],{"class":42},[36,2980,2981],{"class":91}," false",[36,2983,2984],{"class":50},",\n",[36,2986,2987],{"class":38,"line":562},[36,2988,2989],{"class":50},"          ),\n",[36,2991,2992],{"class":38,"line":1063},[36,2993,2994],{"class":50},"        );\n",[36,2996,2997],{"class":38,"line":1068},[36,2998,2320],{"class":50},[36,3000,3001],{"class":38,"line":1079},[36,3002,227],{"class":50},[36,3004,3005],{"class":38,"line":1091},[36,3006,233],{"class":50},[36,3008,3009],{"class":38,"line":1096},[36,3010,239],{"class":50},[36,3012,3013],{"class":38,"line":1106},[36,3014,58],{"emptyLinePlaceholder":57},[36,3016,3017,3019,3022],{"class":38,"line":1112},[36,3018,88],{"class":42},[36,3020,3021],{"class":91}," Item",[36,3023,101],{"class":50},[36,3025,3026,3028,3030],{"class":38,"line":1118},[36,3027,420],{"class":42},[36,3029,423],{"class":91},[36,3031,3032],{"class":50}," id;\n",[36,3034,3035,3037,3039],{"class":38,"line":1127},[36,3036,420],{"class":42},[36,3038,423],{"class":91},[36,3040,3041],{"class":50}," title;\n",[36,3043,3044,3047],{"class":38,"line":1138},[36,3045,3046],{"class":91},"  bool",[36,3048,3049],{"class":50}," checked;\n",[36,3051,3052,3055,3057,3059,3062,3064,3067,3069,3072,3074,3076],{"class":38,"line":1143},[36,3053,3054],{"class":91},"  Item",[36,3056,137],{"class":50},[36,3058,694],{"class":91},[36,3060,3061],{"class":50},".id, ",[36,3063,694],{"class":91},[36,3065,3066],{"class":50},".title, {",[36,3068,694],{"class":91},[36,3070,3071],{"class":50},".checked ",[36,3073,532],{"class":42},[36,3075,2981],{"class":91},[36,3077,705],{"class":50},[36,3079,3080],{"class":38,"line":1148},[36,3081,239],{"class":50},[14,3083,3085],{"id":3084},"state-management-providerriverpod","State Management — Provider\u002FRiverpod",[24,3087,3088],{"language":26},[28,3089,3091],{"className":30,"code":3090,"language":26,"meta":32,"style":32},"import 'package:flutter\u002Fmaterial.dart';\nimport 'package:flutter_riverpod\u002Fflutter_riverpod.dart';\n\n\u002F\u002F ── Riverpod: compile-safe, no BuildContext needed ──\n\n\u002F\u002F A provider holds state and notifies listeners on change.\nfinal counterProvider = StateNotifierProvider\u003CCounterNotifier, int>((ref) {\n  return CounterNotifier();\n});\n\nclass CounterNotifier extends StateNotifier\u003Cint> {\n  CounterNotifier() : super(0);\n\n  void increment() => state++;\n  void decrement() => state--;\n  void reset() => state = 0;\n}\n\n\u002F\u002F Consuming in a widget:\nclass CounterScreen extends ConsumerWidget {\n  const CounterScreen({super.key});\n\n  @override\n  Widget build(BuildContext context, WidgetRef ref) {\n    final count = ref.watch(counterProvider);  \u002F\u002F rebuilds when count changes\n\n    return Scaffold(\n      body: Center(child: Text('Count: $count')),\n      floatingActionButton: FloatingActionButton(\n        onPressed: () => ref.read(counterProvider.notifier).increment(),\n        child: const Icon(Icons.add),\n      ),\n    );\n  }\n}\n\n\u002F\u002F ── AsyncValue for async state (loading, data, error) ──\nfinal userProvider = FutureProvider\u003CUser>((ref) async {\n  return fetchUser();  \u002F\u002F returns AsyncValue\u003CUser>\n});\n\nclass UserWidget extends ConsumerWidget {\n  const UserWidget({super.key});\n\n  @override\n  Widget build(BuildContext context, WidgetRef ref) {\n    final asyncUser = ref.watch(userProvider);\n\n    return asyncUser.when(\n      loading: () => const CircularProgressIndicator(),\n      error: (err, stack) => Text('Error: $err'),\n      data: (user) => Text('Hello, ${user.name}'),\n    );\n  }\n}\n",[19,3092,3093,3101,3110,3114,3119,3123,3128,3154,3163,3167,3171,3188,3207,3211,3229,3247,3267,3271,3275,3280,3294,3306,3310,3314,3333,3354,3358,3366,3397,3409,3433,3452,3457,3461,3465,3469,3473,3478,3501,3512,3516,3520,3533,3545,3549,3553,3569,3585,3589,3601,3619,3647,3682,3686,3690],{"__ignoreMap":32},[36,3094,3095,3097,3099],{"class":38,"line":39},[36,3096,43],{"class":42},[36,3098,47],{"class":46},[36,3100,51],{"class":50},[36,3102,3103,3105,3108],{"class":38,"line":54},[36,3104,43],{"class":42},[36,3106,3107],{"class":46}," 'package:flutter_riverpod\u002Fflutter_riverpod.dart'",[36,3109,51],{"class":50},[36,3111,3112],{"class":38,"line":61},[36,3113,58],{"emptyLinePlaceholder":57},[36,3115,3116],{"class":38,"line":68},[36,3117,3118],{"class":64},"\u002F\u002F ── Riverpod: compile-safe, no BuildContext needed ──\n",[36,3120,3121],{"class":38,"line":74},[36,3122,58],{"emptyLinePlaceholder":57},[36,3124,3125],{"class":38,"line":79},[36,3126,3127],{"class":64},"\u002F\u002F A provider holds state and notifies listeners on change.\n",[36,3129,3130,3132,3135,3137,3140,3142,3145,3148,3151],{"class":38,"line":85},[36,3131,565],{"class":42},[36,3133,3134],{"class":50}," counterProvider ",[36,3136,532],{"class":42},[36,3138,3139],{"class":91}," StateNotifierProvider",[36,3141,721],{"class":50},[36,3143,3144],{"class":91},"CounterNotifier",[36,3146,3147],{"class":50},", ",[36,3149,3150],{"class":91},"int",[36,3152,3153],{"class":50},">((ref) {\n",[36,3155,3156,3158,3161],{"class":38,"line":104},[36,3157,1838],{"class":42},[36,3159,3160],{"class":91}," CounterNotifier",[36,3162,742],{"class":50},[36,3164,3165],{"class":38,"line":121},[36,3166,705],{"class":50},[36,3168,3169],{"class":38,"line":127},[36,3170,58],{"emptyLinePlaceholder":57},[36,3172,3173,3175,3177,3179,3182,3184,3186],{"class":38,"line":146},[36,3174,88],{"class":42},[36,3176,3160],{"class":91},[36,3178,95],{"class":42},[36,3180,3181],{"class":91}," StateNotifier",[36,3183,721],{"class":50},[36,3185,3150],{"class":91},[36,3187,768],{"class":50},[36,3189,3190,3193,3195,3197,3200,3202,3205],{"class":38,"line":158},[36,3191,3192],{"class":91},"  CounterNotifier",[36,3194,733],{"class":50},[36,3196,164],{"class":42},[36,3198,3199],{"class":91}," super",[36,3201,137],{"class":50},[36,3203,3204],{"class":91},"0",[36,3206,500],{"class":50},[36,3208,3209],{"class":38,"line":170},[36,3210,58],{"emptyLinePlaceholder":57},[36,3212,3213,3215,3218,3220,3222,3225,3227],{"class":38,"line":187},[36,3214,803],{"class":42},[36,3216,3217],{"class":133}," increment",[36,3219,733],{"class":50},[36,3221,736],{"class":42},[36,3223,3224],{"class":50}," state",[36,3226,1133],{"class":42},[36,3228,51],{"class":50},[36,3230,3231,3233,3236,3238,3240,3242,3245],{"class":38,"line":202},[36,3232,803],{"class":42},[36,3234,3235],{"class":133}," decrement",[36,3237,733],{"class":50},[36,3239,736],{"class":42},[36,3241,3224],{"class":50},[36,3243,3244],{"class":42},"--",[36,3246,51],{"class":50},[36,3248,3249,3251,3254,3256,3258,3261,3263,3265],{"class":38,"line":218},[36,3250,803],{"class":42},[36,3252,3253],{"class":133}," reset",[36,3255,733],{"class":50},[36,3257,736],{"class":42},[36,3259,3260],{"class":50}," state ",[36,3262,532],{"class":42},[36,3264,702],{"class":91},[36,3266,51],{"class":50},[36,3268,3269],{"class":38,"line":224},[36,3270,239],{"class":50},[36,3272,3273],{"class":38,"line":230},[36,3274,58],{"emptyLinePlaceholder":57},[36,3276,3277],{"class":38,"line":236},[36,3278,3279],{"class":64},"\u002F\u002F Consuming in a widget:\n",[36,3281,3282,3284,3287,3289,3292],{"class":38,"line":242},[36,3283,88],{"class":42},[36,3285,3286],{"class":91}," CounterScreen",[36,3288,95],{"class":42},[36,3290,3291],{"class":91}," ConsumerWidget",[36,3293,101],{"class":50},[36,3295,3296,3298,3300,3302,3304],{"class":38,"line":247},[36,3297,107],{"class":42},[36,3299,3286],{"class":91},[36,3301,112],{"class":50},[36,3303,115],{"class":91},[36,3305,118],{"class":50},[36,3307,3308],{"class":38,"line":253},[36,3309,58],{"emptyLinePlaceholder":57},[36,3311,3312],{"class":38,"line":267},[36,3313,124],{"class":42},[36,3315,3316,3318,3320,3322,3324,3327,3330],{"class":38,"line":280},[36,3317,130],{"class":91},[36,3319,134],{"class":133},[36,3321,137],{"class":50},[36,3323,140],{"class":91},[36,3325,3326],{"class":50}," context, ",[36,3328,3329],{"class":91},"WidgetRef",[36,3331,3332],{"class":50}," ref) {\n",[36,3334,3335,3337,3340,3342,3345,3348,3351],{"class":38,"line":285},[36,3336,1688],{"class":42},[36,3338,3339],{"class":50}," count ",[36,3341,532],{"class":42},[36,3343,3344],{"class":50}," ref.",[36,3346,3347],{"class":133},"watch",[36,3349,3350],{"class":50},"(counterProvider);  ",[36,3352,3353],{"class":64},"\u002F\u002F rebuilds when count changes\n",[36,3355,3356],{"class":38,"line":298},[36,3357,58],{"emptyLinePlaceholder":57},[36,3359,3360,3362,3364],{"class":38,"line":307},[36,3361,149],{"class":42},[36,3363,2458],{"class":91},[36,3365,155],{"class":50},[36,3367,3368,3371,3373,3376,3379,3381,3383,3385,3387,3389,3392,3394],{"class":38,"line":319},[36,3369,3370],{"class":50},"      body",[36,3372,164],{"class":42},[36,3374,3375],{"class":91}," Center",[36,3377,3378],{"class":50},"(child",[36,3380,164],{"class":42},[36,3382,483],{"class":91},[36,3384,137],{"class":50},[36,3386,1215],{"class":46},[36,3388,491],{"class":46},[36,3390,3391],{"class":91},"count",[36,3393,497],{"class":46},[36,3395,3396],{"class":50},")),\n",[36,3398,3399,3402,3404,3407],{"class":38,"line":333},[36,3400,3401],{"class":50},"      floatingActionButton",[36,3403,164],{"class":42},[36,3405,3406],{"class":91}," FloatingActionButton",[36,3408,155],{"class":50},[36,3410,3411,3414,3416,3418,3420,3422,3425,3428,3431],{"class":38,"line":347},[36,3412,3413],{"class":50},"        onPressed",[36,3415,164],{"class":42},[36,3417,2236],{"class":50},[36,3419,736],{"class":42},[36,3421,3344],{"class":50},[36,3423,3424],{"class":133},"read",[36,3426,3427],{"class":50},"(counterProvider.notifier).",[36,3429,3430],{"class":133},"increment",[36,3432,2281],{"class":50},[36,3434,3435,3438,3440,3442,3445,3447,3449],{"class":38,"line":360},[36,3436,3437],{"class":50},"        child",[36,3439,164],{"class":42},[36,3441,314],{"class":42},[36,3443,3444],{"class":91}," Icon",[36,3446,137],{"class":50},[36,3448,210],{"class":91},[36,3450,3451],{"class":50},".add),\n",[36,3453,3454],{"class":38,"line":365},[36,3455,3456],{"class":50},"      ),\n",[36,3458,3459],{"class":38,"line":370},[36,3460,227],{"class":50},[36,3462,3463],{"class":38,"line":375},[36,3464,233],{"class":50},[36,3466,3467],{"class":38,"line":380},[36,3468,239],{"class":50},[36,3470,3471],{"class":38,"line":385},[36,3472,58],{"emptyLinePlaceholder":57},[36,3474,3475],{"class":38,"line":391},[36,3476,3477],{"class":64},"\u002F\u002F ── AsyncValue for async state (loading, data, error) ──\n",[36,3479,3480,3482,3485,3487,3490,3492,3494,3497,3499],{"class":38,"line":397},[36,3481,565],{"class":42},[36,3483,3484],{"class":50}," userProvider ",[36,3486,532],{"class":42},[36,3488,3489],{"class":91}," FutureProvider",[36,3491,721],{"class":50},[36,3493,2363],{"class":91},[36,3495,3496],{"class":50},">((ref) ",[36,3498,1681],{"class":42},[36,3500,101],{"class":50},[36,3502,3503,3505,3507,3509],{"class":38,"line":403},[36,3504,1838],{"class":42},[36,3506,2052],{"class":133},[36,3508,965],{"class":50},[36,3510,3511],{"class":64},"\u002F\u002F returns AsyncValue\u003CUser>\n",[36,3513,3514],{"class":38,"line":417},[36,3515,705],{"class":50},[36,3517,3518],{"class":38,"line":429},[36,3519,58],{"emptyLinePlaceholder":57},[36,3521,3522,3524,3527,3529,3531],{"class":38,"line":455},[36,3523,88],{"class":42},[36,3525,3526],{"class":91}," UserWidget",[36,3528,95],{"class":42},[36,3530,3291],{"class":91},[36,3532,101],{"class":50},[36,3534,3535,3537,3539,3541,3543],{"class":38,"line":460},[36,3536,107],{"class":42},[36,3538,3526],{"class":91},[36,3540,112],{"class":50},[36,3542,115],{"class":91},[36,3544,118],{"class":50},[36,3546,3547],{"class":38,"line":465},[36,3548,58],{"emptyLinePlaceholder":57},[36,3550,3551],{"class":38,"line":478},[36,3552,124],{"class":42},[36,3554,3555,3557,3559,3561,3563,3565,3567],{"class":38,"line":503},[36,3556,130],{"class":91},[36,3558,134],{"class":133},[36,3560,137],{"class":50},[36,3562,140],{"class":91},[36,3564,3326],{"class":50},[36,3566,3329],{"class":91},[36,3568,3332],{"class":50},[36,3570,3571,3573,3576,3578,3580,3582],{"class":38,"line":508},[36,3572,1688],{"class":42},[36,3574,3575],{"class":50}," asyncUser ",[36,3577,532],{"class":42},[36,3579,3344],{"class":50},[36,3581,3347],{"class":133},[36,3583,3584],{"class":50},"(userProvider);\n",[36,3586,3587],{"class":38,"line":513},[36,3588,58],{"emptyLinePlaceholder":57},[36,3590,3591,3593,3596,3599],{"class":38,"line":518},[36,3592,149],{"class":42},[36,3594,3595],{"class":50}," asyncUser.",[36,3597,3598],{"class":42},"when",[36,3600,155],{"class":50},[36,3602,3603,3606,3608,3610,3612,3614,3617],{"class":38,"line":524},[36,3604,3605],{"class":50},"      loading",[36,3607,164],{"class":42},[36,3609,2236],{"class":50},[36,3611,736],{"class":42},[36,3613,314],{"class":42},[36,3615,3616],{"class":91}," CircularProgressIndicator",[36,3618,2281],{"class":50},[36,3620,3621,3624,3626,3629,3631,3633,3635,3638,3640,3643,3645],{"class":38,"line":551},[36,3622,3623],{"class":50},"      error",[36,3625,164],{"class":42},[36,3627,3628],{"class":50}," (err, stack) ",[36,3630,736],{"class":42},[36,3632,483],{"class":91},[36,3634,137],{"class":50},[36,3636,3637],{"class":46},"'Error: ",[36,3639,491],{"class":46},[36,3641,3642],{"class":91},"err",[36,3644,497],{"class":46},[36,3646,1225],{"class":50},[36,3648,3649,3652,3654,3657,3659,3661,3663,3665,3668,3671,3673,3675,3678,3680],{"class":38,"line":556},[36,3650,3651],{"class":50},"      data",[36,3653,164],{"class":42},[36,3655,3656],{"class":50}," (user) ",[36,3658,736],{"class":42},[36,3660,483],{"class":91},[36,3662,137],{"class":50},[36,3664,488],{"class":46},[36,3666,3667],{"class":46},"${",[36,3669,3670],{"class":91},"user",[36,3672,582],{"class":46},[36,3674,494],{"class":91},[36,3676,3677],{"class":46},"}",[36,3679,497],{"class":46},[36,3681,1225],{"class":50},[36,3683,3684],{"class":38,"line":562},[36,3685,227],{"class":50},[36,3687,3688],{"class":38,"line":1063},[36,3689,233],{"class":50},[36,3691,3692],{"class":38,"line":1068},[36,3693,239],{"class":50},[14,3695,3697],{"id":3696},"tips-tricks","💡 Tips & Tricks",[3699,3700,3701,3722,3743,3759,3771],"ul",{},[3702,3703,3704,3708,3709,3711,3712,3715,3716,3718,3719,3721],"li",{},[3705,3706,3707],"strong",{},"Performance",": mark every static widget ",[19,3710,21],{}," — ",[19,3713,3714],{},"const Text('hello')"," is canonicalized (one instance, reused across rebuilds). Zero allocation, zero diffing. Mark constructors ",[19,3717,21],{}," and use ",[19,3720,21],{}," at call sites. This is the #1 Flutter performance optimization.",[3702,3723,3724,3727,3728,3730,3731,3733,3734,3736,3737,3739,3740,3742],{},[3705,3725,3726],{},"Idiom",": ",[19,3729,1329],{}," must be pure — no side effects, no async work, no ",[19,3732,1035],{},". It can be called many times (every rebuild). Start async work in ",[19,3735,819],{},", check ",[19,3738,1856],{}," before ",[19,3741,1035],{}," (the widget may have been disposed while awaiting).",[3702,3744,3745,3747,3748,3750,3751,3754,3755,3758],{},[3705,3746,3726],{},": use ",[19,3749,2481],{}," (not ",[19,3752,3753],{},"ListView"," with all children) for long lists — it builds items lazily (only visible ones), efficient for 1000s of items. ",[19,3756,3757],{},"ListView(children: [...])"," builds all, slow for long lists.",[3702,3760,3761,3747,3763,3766,3767,3770],{},[3705,3762,3726],{},[19,3764,3765],{},"ValueKey"," for items that can reorder — Flutter matches by type by default, so state can jump to the wrong item on reorder. ",[19,3768,3769],{},"key: ValueKey(item.id)"," preserves state per item identity.",[3702,3772,3773,3747,3775,3778,3779,3782,3783,3786],{},[3705,3774,3726],{},[19,3776,3777],{},"Theme.of(context)"," for styling — ",[19,3780,3781],{},"Theme.of(context).colorScheme.primary"," instead of hardcoding colors. Adapts to light\u002Fdark mode and centralizes the design system. Access in ",[19,3784,3785],{},"build"," (reactive to theme changes).",[14,3788,3790],{"id":3789},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[3699,3792,3793,3809,3833,3847,3876,3892,3905,3918,3933,3939],{},[3702,3794,3795,3727,3800,3802,3803,3805,3806,3808],{},[3705,3796,3797,3799],{},[19,3798,1329],{}," must be pure",[19,3801,3785],{}," can be called many times (every rebuild). Don't start async work, mutate state, or do I\u002FO in ",[19,3804,3785],{},". Use ",[19,3807,819],{}," for setup.",[3702,3810,3811,3727,3821,3815,3823,3825,3826,3828,3829,3832],{},[3705,3812,3813,3815,3816,3818,3819],{},[19,3814,1035],{}," in ",[19,3817,3785],{}," or ",[19,3820,819],{},[19,3822,1035],{},[19,3824,3785],{}," causes an infinite loop. In ",[19,3827,819],{},", use ",[19,3830,3831],{},"WidgetsBinding.instance.addPostFrameCallback"," to defer.",[3702,3834,3835,3727,3840,3843,3844,3846],{},[3705,3836,3837,3839],{},[19,3838,21],{}," widgets are canonicalized",[19,3841,3842],{},"const Text('hi')"," is the same instance everywhere. Good for perf. But a ",[19,3845,21],{}," widget can't use runtime values — only compile-time constants.",[3702,3848,3849,3854,3855,3858,3859,3862,3863,3866,3867,3869,3870,3872,3873,3875],{},[3705,3850,3851,3853],{},[19,3852,140],{}," across async gaps",": after ",[19,3856,3857],{},"await",", the ",[19,3860,3861],{},"context"," may be unmounted (the widget was disposed). Check ",[19,3864,3865],{},"if (!context.mounted) return;"," before using ",[19,3868,3861],{}," after ",[19,3871,3857],{}," (Dart 3.7+). Or check ",[19,3874,1856],{}," (State property).",[3702,3877,3878,3883,3884,3887,3888,3891],{},[3705,3879,3880,3882],{},[19,3881,603],{},"'s state persists across widget rebuilds",": a new ",[19,3885,3886],{},"MyWidget"," instance on parent rebuild, but Flutter reuses the ",[19,3889,3890],{},"State"," (matched by type\u002Fkey). The state isn't lost.",[3702,3893,3894,3900,3901,3904],{},[3705,3895,3896,3899],{},[19,3897,3898],{},"Key"," for state preservation",": when a widget's position in the tree changes (e.g., list reorders), Flutter matches by type by default — state can be lost. Use ",[19,3902,3903],{},"key: ValueKey(id)"," to preserve state across reorders.",[3702,3906,3907,3727,3912,3914,3915,3917],{},[3705,3908,3909,3911],{},[19,3910,2481],{}," for long lists",[19,3913,3757],{}," builds all children eagerly — slow for 1000s of items. ",[19,3916,2481],{}," is lazy (only visible items).",[3702,3919,3920,3727,3926,3929,3930,3932],{},[3705,3921,3922,3925],{},[19,3923,3924],{},"MediaQuery.of(context)"," for screen size",[19,3927,3928],{},"MediaQuery.of(context).size.width"," — access screen dimensions. Call in ",[19,3931,3785],{}," (reactive to orientation\u002Fsize changes).",[3702,3934,3935,3938],{},[3705,3936,3937],{},"Platform channels for native code",": most native features (camera, sensors) are in packages. Use platform channels only for custom native code. It's verbose (Kotlin\u002FSwift handler).",[3702,3940,3941,3944,3945,3947,3948,3951],{},[3705,3942,3943],{},"Hot reload vs state",": hot reload preserves state (great for iteration). But some changes (e.g., ",[19,3946,819],{}," logic) need a hot restart (",[19,3949,3950],{},"R",") to take effect.",[14,3953,3955],{"id":3954},"spot-the-bug","🧠 Spot the Bug",[3957,3958,3959,3960,3962,3963,3965],"p",{},"A developer fetches data in ",[19,3961,1329],{}," and calls ",[19,3964,1035],{}," when it completes, but the app loops:",[24,3967,3968],{"language":26},[28,3969,3971],{"className":30,"code":3970,"language":26,"meta":32,"style":32},"@override\nWidget build(BuildContext context) {\n  fetchData().then((data) {\n    setState(() => _data = data);\n  });\n  return Text(_data ?? 'Loading...');\n}\n",[19,3972,3973,3978,3991,4002,4016,4021,4035],{"__ignoreMap":32},[36,3974,3975],{"class":38,"line":39},[36,3976,3977],{"class":42},"@override\n",[36,3979,3980,3983,3985,3987,3989],{"class":38,"line":54},[36,3981,3982],{"class":91},"Widget",[36,3984,134],{"class":133},[36,3986,137],{"class":50},[36,3988,140],{"class":91},[36,3990,143],{"class":50},[36,3992,3993,3996,3998,4000],{"class":38,"line":61},[36,3994,3995],{"class":133},"  fetchData",[36,3997,588],{"class":50},[36,3999,1473],{"class":133},[36,4001,1476],{"class":50},[36,4003,4004,4006,4008,4010,4012,4014],{"class":38,"line":68},[36,4005,1121],{"class":133},[36,4007,1038],{"class":50},[36,4009,736],{"class":42},[36,4011,1488],{"class":50},[36,4013,532],{"class":42},[36,4015,1726],{"class":50},[36,4017,4018],{"class":38,"line":74},[36,4019,4020],{"class":50},"  });\n",[36,4022,4023,4025,4027,4029,4031,4033],{"class":38,"line":79},[36,4024,1838],{"class":42},[36,4026,483],{"class":91},[36,4028,1509],{"class":50},[36,4030,1512],{"class":42},[36,4032,1515],{"class":46},[36,4034,500],{"class":50},[36,4036,4037],{"class":38,"line":85},[36,4038,239],{"class":50},[3957,4040,4041],{},"Two problems — what are they?",[4043,4044,4045,4049,4093,4103,4253],"details",{},[4046,4047,4048],"summary",{},"Answer",[4050,4051,4052,4079],"ol",{},[3702,4053,4054,3727,4057,4059,4060,4063,4064,4066,4067,4069,4070,4072,4073,4075,4076,4078],{},[3705,4055,4056],{},"Infinite loop",[19,4058,1329],{}," calls ",[19,4061,4062],{},"fetchData()",". When the fetch completes, ",[19,4065,1035],{}," triggers a rebuild. ",[19,4068,1329],{}," runs again, calling ",[19,4071,4062],{}," again. The fetch completes, ",[19,4074,1035],{}," fires, ",[19,4077,1329],{}," runs, fetch starts... infinite loop.",[3702,4080,4081,4086,4087,4089,4090,582],{},[3705,4082,4083,4085],{},[19,4084,1035],{}," after dispose",": if the widget is unmounted (navigated away) before the fetch completes, ",[19,4088,1035],{}," throws ",[19,4091,4092],{},"\"setState() called after dispose()\"",[3957,4094,4095,4096,4098,4099,3739,4101,164],{},"The fix — start the fetch in ",[19,4097,819],{}," (runs once), and check ",[19,4100,1856],{},[19,4102,1035],{},[28,4104,4106],{"className":30,"code":4105,"language":26,"meta":32,"style":32},"@override\nvoid initState() {\n  super.initState();\n  _loadData();  \u002F\u002F runs once, not on every build\n}\n\nFuture\u003Cvoid> _loadData() async {\n  final data = await fetchData();\n  if (mounted) {  \u002F\u002F widget may have been disposed during the await\n    setState(() => _data = data);\n  }\n}\n\n@override\nWidget build(BuildContext context) {\n  return Text(_data ?? 'Loading...');  \u002F\u002F pure — reads state, returns tree\n}\n",[19,4107,4108,4112,4120,4131,4141,4145,4149,4167,4181,4191,4205,4209,4213,4217,4221,4233,4249],{"__ignoreMap":32},[36,4109,4110],{"class":38,"line":39},[36,4111,3977],{"class":42},[36,4113,4114,4116,4118],{"class":38,"line":54},[36,4115,1671],{"class":42},[36,4117,806],{"class":133},[36,4119,809],{"class":50},[36,4121,4122,4125,4127,4129],{"class":38,"line":61},[36,4123,4124],{"class":91},"  super",[36,4126,582],{"class":50},[36,4128,819],{"class":133},[36,4130,742],{"class":50},[36,4132,4133,4136,4138],{"class":38,"line":68},[36,4134,4135],{"class":133},"  _loadData",[36,4137,965],{"class":50},[36,4139,4140],{"class":64},"\u002F\u002F runs once, not on every build\n",[36,4142,4143],{"class":38,"line":74},[36,4144,239],{"class":50},[36,4146,4147],{"class":38,"line":79},[36,4148,58],{"emptyLinePlaceholder":57},[36,4150,4151,4153,4155,4157,4159,4161,4163,4165],{"class":38,"line":85},[36,4152,1788],{"class":91},[36,4154,721],{"class":50},[36,4156,1671],{"class":42},[36,4158,727],{"class":50},[36,4160,1676],{"class":133},[36,4162,733],{"class":50},[36,4164,1681],{"class":42},[36,4166,101],{"class":50},[36,4168,4169,4171,4173,4175,4177,4179],{"class":38,"line":104},[36,4170,420],{"class":42},[36,4172,1691],{"class":50},[36,4174,532],{"class":42},[36,4176,1696],{"class":42},[36,4178,1699],{"class":133},[36,4180,742],{"class":50},[36,4182,4183,4186,4188],{"class":38,"line":121},[36,4184,4185],{"class":42},"  if",[36,4187,1708],{"class":50},[36,4189,4190],{"class":64},"\u002F\u002F widget may have been disposed during the await\n",[36,4192,4193,4195,4197,4199,4201,4203],{"class":38,"line":127},[36,4194,1121],{"class":133},[36,4196,1038],{"class":50},[36,4198,736],{"class":42},[36,4200,1488],{"class":50},[36,4202,532],{"class":42},[36,4204,1726],{"class":50},[36,4206,4207],{"class":38,"line":146},[36,4208,233],{"class":50},[36,4210,4211],{"class":38,"line":158},[36,4212,239],{"class":50},[36,4214,4215],{"class":38,"line":170},[36,4216,58],{"emptyLinePlaceholder":57},[36,4218,4219],{"class":38,"line":187},[36,4220,3977],{"class":42},[36,4222,4223,4225,4227,4229,4231],{"class":38,"line":202},[36,4224,3982],{"class":91},[36,4226,134],{"class":133},[36,4228,137],{"class":50},[36,4230,140],{"class":91},[36,4232,143],{"class":50},[36,4234,4235,4237,4239,4241,4243,4245,4247],{"class":38,"line":218},[36,4236,1838],{"class":42},[36,4238,483],{"class":91},[36,4240,1509],{"class":50},[36,4242,1512],{"class":42},[36,4244,1515],{"class":46},[36,4246,545],{"class":50},[36,4248,1771],{"class":64},[36,4250,4251],{"class":38,"line":224},[36,4252,239],{"class":50},[3957,4254,4255,4257,4258,4261,4262,4264,4265,4267],{},[19,4256,819],{}," runs once when the State is created. ",[19,4259,4260],{},"if (mounted)"," checks the widget is still in the tree before ",[19,4263,1035],{}," (avoids the \"setState after dispose\" error). ",[19,4266,1329],{}," is now pure — no side effects.",[4269,4270,4271],"style",{},"html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}",{"title":32,"searchDepth":54,"depth":54,"links":4273},[4274,4276,4278,4280,4282,4284,4285,4286,4287],{"id":16,"depth":54,"text":4275},"Widget Tree — const Canonicalization & Rebuild Performance",{"id":600,"depth":54,"text":4277},"StatefulWidget Lifecycle — The Two-Class Design",{"id":1326,"depth":54,"text":4279},"build() Purity — The Side-Effect Trap",{"id":1850,"depth":54,"text":4281},"BuildContext — The mounted Check After Await",{"id":2478,"depth":54,"text":4283},"ListView.builder — Lazy Building for Long Lists",{"id":3084,"depth":54,"text":3085},{"id":3696,"depth":54,"text":3697},{"id":3789,"depth":54,"text":3790},{"id":3954,"depth":54,"text":3955},"Deep-dive into Flutter's widget tree diffing, StatefulWidget lifecycle, const canonicalization for performance, build purity, context-after-await safety, and state management patterns. Code-first engineering reference.","md",{},"\u002Fdart\u002F16-flutter-essentials",{"title":5,"description":4288},"dart\u002F16-flutter-essentials","qNCLTT8twjEBlwW8rgMF_OZPbgPdK286YSZU0NzF81Q",1789924647976]