[{"data":1,"prerenderedAt":2395},["ShallowReactive",2],{"navigation_docs_en":3,"-en-examples-hooks-integration":342,"-en-examples-hooks-integration-surround":2390},[4,45,91,137,195,236,257,291,327],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","/en/getting-started","en/01.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"What is Qora?","/en/getting-started/what-is-qora","en/01.getting-started/2.what-is-qora","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Installation","/en/getting-started/installation","en/01.getting-started/3.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":6},"Quick Start","/en/getting-started/quick-start","en/01.getting-started/4.quick-start",{"title":25,"path":26,"stem":27,"icon":28},"Comparison","/en/getting-started/comparison","en/01.getting-started/5.comparison","i-lucide-scale",{"title":30,"path":31,"stem":32,"icon":33},"Coming from TanStack Query","/en/getting-started/coming-from-tanstack-query","en/01.getting-started/6.coming-from-tanstack-query","i-lucide-arrow-left-right",{"title":35,"path":36,"stem":37,"icon":38},"Migrating from Other Libraries","/en/getting-started/migrating-from-other-libraries","en/01.getting-started/7.migrating-from-other-libraries","i-lucide-arrow-right-left",{"title":40,"path":41,"stem":42,"icon":43},"AI Assistants","/en/getting-started/ai-assistants","en/01.getting-started/8.ai-assistants","i-lucide-sparkles",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Core Concepts","i-lucide-book-open","/en/core-concepts","en/02.core-concepts",[51,56,61,66,71,76,81,86],{"title":52,"path":53,"stem":54,"icon":55},"Queries","/en/core-concepts/queries","en/02.core-concepts/1.queries","i-lucide-database",{"title":57,"path":58,"stem":59,"icon":60},"Query Keys","/en/core-concepts/query-keys","en/02.core-concepts/2.query-keys","i-lucide-key-round",{"title":62,"path":63,"stem":64,"icon":65},"Query States","/en/core-concepts/query-states","en/02.core-concepts/3.query-states","i-lucide-activity",{"title":67,"path":68,"stem":69,"icon":70},"Caching","/en/core-concepts/caching","en/02.core-concepts/4.caching","i-lucide-layers-3",{"title":72,"path":73,"stem":74,"icon":75},"Stale-While-Revalidate","/en/core-concepts/stale-while-revalidate","en/02.core-concepts/5.stale-while-revalidate","i-lucide-timer-reset",{"title":77,"path":78,"stem":79,"icon":80},"Deduplication","/en/core-concepts/deduplication","en/02.core-concepts/6.deduplication","i-lucide-copy-minus",{"title":82,"path":83,"stem":84,"icon":85},"Mutations & Invalidation","/en/core-concepts/mutations","en/02.core-concepts/7.mutations","i-lucide-pencil-line",{"title":87,"path":88,"stem":89,"icon":90},"Offline & Network","/en/core-concepts/offline","en/02.core-concepts/8.offline","i-lucide-wifi-off",{"title":92,"icon":93,"path":94,"stem":95,"children":96,"page":44},"Flutter Integration","i-lucide-smartphone","/en/flutter-integration","en/03.flutter-integration",[97,102,107,112,117,122,127,132],{"title":98,"path":99,"stem":100,"icon":101},"Setup","/en/flutter-integration/setup","en/03.flutter-integration/1.setup","i-lucide-wrench",{"title":103,"path":104,"stem":105,"icon":106},"QoraScope","/en/flutter-integration/qora-scope","en/03.flutter-integration/2.qora-scope","i-lucide-share-2",{"title":108,"path":109,"stem":110,"icon":111},"QoraBuilder","/en/flutter-integration/qora-builder","en/03.flutter-integration/3.qora-builder","i-lucide-blocks",{"title":113,"path":114,"stem":115,"icon":116},"QoraMutationBuilder","/en/flutter-integration/qora-mutation-builder","en/03.flutter-integration/4.qora-mutation-builder","i-lucide-pencil",{"title":118,"path":119,"stem":120,"icon":121},"InfiniteQueryBuilder","/en/flutter-integration/infinite-query-builder","en/03.flutter-integration/5.infinite-query-builder","i-lucide-infinity",{"title":123,"path":124,"stem":125,"icon":126},"Hooks (flutter_hooks)","/en/flutter-integration/hooks","en/03.flutter-integration/6.hooks","i-lucide-anchor",{"title":128,"path":129,"stem":130,"icon":131},"Network Status Widgets","/en/flutter-integration/network-status","en/03.flutter-integration/7.network-status","i-lucide-wifi",{"title":133,"path":134,"stem":135,"icon":136},"Best Practices","/en/flutter-integration/best-practices","en/03.flutter-integration/8.best-practices","i-lucide-badge-check",{"title":138,"icon":139,"path":140,"stem":141,"children":142,"page":44},"Recipes","i-lucide-chef-hat","/en/recipes","en/04.recipes",[143,147,152,157,162,166,171,176,181,186,191],{"title":144,"path":145,"stem":146,"icon":85},"Mutations","/en/recipes/mutations","en/04.recipes/02.mutations",{"title":148,"path":149,"stem":150,"icon":151},"Optimistic Updates","/en/recipes/optimistic-updates","en/04.recipes/03.optimistic-updates","i-lucide-zap",{"title":153,"path":154,"stem":155,"icon":156},"Persistence","/en/recipes/persistence","en/04.recipes/04.persistence","i-lucide-hard-drive",{"title":158,"path":159,"stem":160,"icon":161},"Network Aware","/en/recipes/network-aware","en/04.recipes/05.network-aware","i-lucide-signal",{"title":163,"path":164,"stem":165,"icon":121},"Infinite Queries","/en/recipes/infinite-queries","en/04.recipes/06.infinite-queries",{"title":167,"path":168,"stem":169,"icon":170},"Dependent Queries","/en/recipes/dependent-queries","en/04.recipes/07.dependent-queries","i-lucide-link-2",{"title":172,"path":173,"stem":174,"icon":175},"Cancellation","/en/recipes/cancel-token","en/04.recipes/08.cancel-token","i-lucide-circle-slash",{"title":177,"path":178,"stem":179,"icon":180},"SSR Hydration","/en/recipes/ssr-hydration","en/04.recipes/09.ssr-hydration","i-lucide-server",{"title":182,"path":183,"stem":184,"icon":185},"Error Handling","/en/recipes/error-handling","en/04.recipes/10.error-handling","i-lucide-shield-alert",{"title":187,"path":188,"stem":189,"icon":190},"Testing","/en/recipes/testing","en/04.recipes/11.testing","i-lucide-flask-conical",{"title":192,"path":193,"stem":194},"Route-Level Prefetching","/en/recipes/prefetch","en/04.recipes/12.prefetch",{"title":196,"icon":197,"path":198,"stem":199,"children":200,"page":44},"API Reference","i-lucide-file-code","/en/api-reference","en/05.api-reference",[201,206,210,214,219,224,228,232],{"title":202,"path":203,"stem":204,"icon":205},"QoraClient","/en/api-reference/qora-client","en/05.api-reference/1.qora-client","i-lucide-cpu",{"title":207,"path":208,"stem":209,"icon":60},"QoraKey","/en/api-reference/qora-key","en/05.api-reference/2.qora-key",{"title":211,"path":212,"stem":213,"icon":65},"QoraState","/en/api-reference/qora-state","en/05.api-reference/3.qora-state",{"title":215,"path":216,"stem":217,"icon":218},"QoraOptions","/en/api-reference/qora-options","en/05.api-reference/4.qora-options","i-lucide-sliders-horizontal",{"title":220,"path":221,"stem":222,"icon":223},"QoraClientConfig","/en/api-reference/qora-client-config","en/05.api-reference/5.qora-client-config","i-lucide-settings-2",{"title":225,"path":226,"stem":227,"icon":85},"Mutation API","/en/api-reference/qora-mutation","en/05.api-reference/6.qora-mutation",{"title":229,"path":230,"stem":231,"icon":156},"PersistQoraClient","/en/api-reference/persist-qora-client","en/05.api-reference/7.persist-qora-client",{"title":233,"path":234,"stem":235,"icon":121},"Infinite Query","/en/api-reference/infinite-query","en/05.api-reference/8.infinite-query",{"title":237,"icon":238,"path":239,"stem":240,"children":241,"page":44},"DevTools","i-lucide-bug","/en/devtools","en/06.devtools",[242,247,252],{"title":243,"path":244,"stem":245,"icon":246},"Overview","/en/devtools/overview","en/06.devtools/1.overview","i-lucide-layout-dashboard",{"title":248,"path":249,"stem":250,"icon":251},"In-App Overlay","/en/devtools/overlay","en/06.devtools/2.overlay","i-lucide-layers",{"title":253,"path":254,"stem":255,"icon":256},"Data Serialization","/en/devtools/data-display","en/06.devtools/4.data-display","i-lucide-eye",{"title":258,"icon":259,"path":260,"stem":261,"children":262,"page":44},"Third Party","i-lucide-puzzle","/en/third-party","en/07.third-party",[263,268,272,277,282,286],{"title":264,"path":265,"stem":266,"icon":267},"With Provider","/en/third-party/with-provider","en/07.third-party/1.with-provider","i-lucide-plug",{"title":269,"path":270,"stem":271,"icon":111},"With BLoC","/en/third-party/with-bloc","en/07.third-party/2.with-bloc",{"title":273,"path":274,"stem":275,"icon":276},"With Riverpod","/en/third-party/with-riverpod","en/07.third-party/3.with-riverpod","i-lucide-droplets",{"title":278,"path":279,"stem":280,"icon":281},"With RxDart","/en/third-party/with-rxdart","en/07.third-party/4.with-rxdart","i-lucide-git-branch",{"title":283,"path":284,"stem":285},"With Dio","/en/third-party/with-dio","en/07.third-party/5.with-dio",{"title":287,"path":288,"stem":289,"icon":290},"With GraphQL","/en/third-party/with-graphql","en/07.third-party/6.with-graphql","i-lucide-binary",{"title":292,"icon":190,"path":293,"stem":294,"children":295,"page":44},"Examples","/en/examples","en/08.examples",[296,301,305,310,314,318,322],{"title":297,"path":298,"stem":299,"icon":300},"Case Study: User List & Detail","/en/examples/basic-query","en/08.examples/1.basic-query","i-lucide-play-circle",{"title":302,"path":303,"stem":304,"icon":151},"Case Study: Optimistic Mutations & Rollback","/en/examples/mutations-optimistic","en/08.examples/2.mutations-optimistic",{"title":306,"path":307,"stem":308,"icon":309},"Case Study: Infinite Scroll Feed","/en/examples/infinite-scroll","en/08.examples/3.infinite-scroll","i-lucide-scroll",{"title":311,"path":312,"stem":313,"icon":90},"Case Study: Offline-First Todo App","/en/examples/offline-first","en/08.examples/4.offline-first",{"title":315,"path":316,"stem":317,"icon":161},"Case Study: Network Awareness","/en/examples/network-awareness","en/08.examples/5.network-awareness",{"title":319,"path":320,"stem":321,"icon":126},"Case Study: Hooks Integration","/en/examples/hooks-integration","en/08.examples/6.hooks-integration",{"title":323,"path":324,"stem":325,"icon":326},"Case Study: Complete Todo App","/en/examples/complete-todo-app","en/08.examples/7.complete-todo-app","i-lucide-check-square",{"title":328,"icon":329,"path":330,"stem":331,"children":332,"page":44},"Help","i-lucide-life-buoy","/en/help","en/09.help",[333,338],{"title":334,"path":335,"stem":336,"icon":337},"FAQ","/en/help/faq","en/09.help/1.faq","i-lucide-circle-help",{"title":339,"path":340,"stem":341,"icon":101},"Troubleshooting","/en/help/troubleshooting","en/09.help/2.troubleshooting",{"id":343,"title":319,"body":344,"description":2381,"extension":2382,"links":2383,"meta":2384,"navigation":2385,"path":320,"seo":2386,"stem":321,"__hash__":2389},"docs_en/en/08.examples/6.hooks-integration.md",{"type":345,"value":346,"toc":2363},"minimark",[347,352,364,382,385,389,517,519,523,558,568,589,591,595,602,620,1405,1421,1427,1433,1481,1521,1527,1538,1709,1729,1736,1746,2195,2202,2204,2208,2214,2223,2225,2229,2316,2318,2322,2359],[348,349,351],"h2",{"id":350},"objective","Objective",[353,354,355,359,360,363],"p",{},[356,357,358],"strong",{},"Context",": ",[361,362,108],"code",{}," introduces nested builder callbacks on screens that combine read and write operations. This structure increases indentation depth and reduces maintainability on complex views.",[353,365,366,369,370,373,374,377,378,381],{},[361,367,368],{},"qora_hooks"," flattens this structure. ",[361,371,372],{},"useQuery"," and ",[361,375,376],{},"useMutation"," are declared at the top of ",[361,379,380],{},"build()",", and the widget tree is rendered from plain values. Cache semantics and deduplication remain identical.",[383,384],"hr",{},[348,386,388],{"id":387},"key-features-demonstrated","Key Features Demonstrated",[390,391,392,405,436,459,477,496,508],"ul",{},[393,394,395,400,401,404],"li",{},[356,396,397],{},[361,398,399],{},"useQuery\u003CT>",": subscribes to a query, returns ",[361,402,403],{},"QoraState\u003CT>"," as a plain value; re-renders on every state change",[393,406,407,412,413,416,417,420,421,420,424,420,427,420,430,420,433],{},[356,408,409],{},[361,410,411],{},"useMutation\u003CTData, TVariables>",": returns a ",[361,414,415],{},"MutationHandle"," with ",[361,418,419],{},"mutate",", ",[361,422,423],{},"mutateAsync",[361,425,426],{},"isPending",[361,428,429],{},"isError",[361,431,432],{},"data",[361,434,435],{},"reset",[393,437,438,443,444,416,447,420,450,420,453,420,456],{},[356,439,440],{},[361,441,442],{},"useInfiniteQuery\u003CTData, TPageParam>",": returns an ",[361,445,446],{},"InfiniteQueryHandle",[361,448,449],{},"pages",[361,451,452],{},"fetchNextPage",[361,454,455],{},"hasNextPage",[361,457,458],{},"isFetchingNextPage",[393,460,461,466,467,469,470,420,473,476],{},[356,462,463],{},[361,464,465],{},"useQueryClient",": returns the nearest ",[361,468,202],{}," for imperative operations (",[361,471,472],{},"invalidate",[361,474,475],{},"setQueryData",")",[393,478,479,484,485,359,488,491,492,495],{},[356,480,481],{},[361,482,483],{},"useIsFetching",": global ",[361,486,487],{},"bool",[361,489,490],{},"true"," while any query has a request in flight: drives a top-level ",[361,493,494],{},"LinearProgressIndicator"," without coupling to individual queries",[393,497,498,484,503,359,505,507],{},[356,499,500],{},[361,501,502],{},"useIsMutating",[361,504,487],{},[361,506,490],{}," while any mutation is pending: disables submit buttons app-wide",[393,509,510,513,514,516],{},[356,511,512],{},"Hook composition",": multiple hooks in one ",[361,515,380],{}," method; they share the same underlying cache transparently",[383,518],{},[348,520,522],{"id":521},"architecture-highlights","Architecture Highlights",[353,524,525,526,528,529,531,532,420,535,420,538,541,542,373,545,548,549,551,552,420,555,557],{},"The package is a thin adapter. Every hook calls the same ",[361,527,202],{}," methods that ",[361,530,108],{}," uses: ",[361,533,534],{},"watchQuery",[361,536,537],{},"watchState",[361,539,540],{},"watchFetchStatus",": via ",[361,543,544],{},"useEffect",[361,546,547],{},"useState",". The cache is shared: if a ",[361,550,108],{}," already fetched ",[361,553,554],{},"['users', id]",[361,556,372],{}," gets it on the first frame from the same entry.",[559,560,566],"pre",{"className":561,"code":563,"language":564,"meta":565},[562],"language-text","qora_hooks/\n└── lib/src/hooks/\n    ├── use_query.dart          ← useState(client.getQueryState) + useEffect(watchQuery.listen)\n    ├── use_mutation.dart       ← useRef(MutationController) + useState(MutationState)\n    ├── use_infinite_query.dart ← useState(InfiniteQueryState) + useEffect(observer.stream.listen)\n    ├── use_query_client.dart   ← QoraScope.of(context)\n    ├── use_is_fetching.dart    ← client.fetchingCountStream.listen\n    └── use_is_mutating.dart    ← client.mutationEvents + activeMutations\n","text","",[361,567,563],{"__ignoreMap":565},[353,569,570,571,574,575,578,579,373,582,585,586,588],{},"Widgets must extend ",[361,572,573],{},"HookWidget"," (or ",[361,576,577],{},"HookConsumerWidget"," for Riverpod). Standard ",[361,580,581],{},"StatelessWidget",[361,583,584],{},"StatefulWidget"," are not supported: use ",[361,587,108],{}," instead.",[383,590],{},[348,592,594],{"id":593},"implementation-details","Implementation Details",[596,597,599,600],"h3",{"id":598},"hook-composition-a-complete-screen-in-one-build","Hook composition: a complete screen in one ",[361,601,380],{},[353,603,604,605,607,608,607,610,612,613,615,616,619],{},"The flagship pattern: ",[361,606,372],{}," + ",[361,609,376],{},[361,611,465],{}," in the same ",[361,614,380],{}," method, no nesting, no custom ",[361,617,618],{},"State",":",[559,621,626],{"className":622,"code":623,"filename":624,"language":625,"meta":565,"style":565},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","class ProfileScreen extends HookWidget {\n  final String userId;\n  const ProfileScreen({super.key, required this.userId});\n\n  @override\n  Widget build(BuildContext context) {\n    // ── Data ─────────────────────────────────────────────────────────────\n    final client   = useQueryClient();\n    final userQuery = useQuery\u003CUser>(\n      key: ['users', userId],\n      fetcher: () => Api.getUser(userId),\n      options: const QoraOptions(staleTime: Duration(minutes: 5)),\n    );\n    final updateMutation = useMutation\u003CUser, UpdateUserInput>(\n      mutator: Api.updateUser,\n      options: MutationOptions(\n        onSuccess: (user, _, __) async =>\n            client.invalidate(['users', userId]),\n      ),\n    );\n\n    // ── UI ───────────────────────────────────────────────────────────────\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Profile'),\n        actions: [\n          if (updateMutation.isError)\n            IconButton(\n              icon: const Icon(Icons.warning_amber, color: Colors.orange),\n              tooltip: 'Save failed: tap to retry',\n              onPressed: updateMutation.reset,\n            ),\n        ],\n      ),\n      body: switch (userQuery) {\n        Initial() || Loading(previousData: null) =>\n            const Center(child: CircularProgressIndicator()),\n        Failure(:final error, previousData: null) => ErrorScreen(error),\n        _ => ProfileForm(\n            user:        userQuery.dataOrNull!,\n            isSaving:    updateMutation.isPending,\n            saveError:   updateMutation.error,\n            onSave: (input) => updateMutation.mutate(input),\n          ),\n      },\n    );\n  }\n}\n","lib/features/profile/ui/profile_screen.dart","dart",[361,627,628,651,667,700,707,713,732,739,759,781,804,831,867,875,899,916,929,957,979,987,994,999,1005,1016,1029,1051,1062,1076,1084,1124,1137,1154,1162,1170,1177,1191,1220,1242,1279,1292,1311,1328,1346,1370,1378,1386,1393,1399],{"__ignoreMap":565},[629,630,633,637,641,644,647],"span",{"class":631,"line":632},"line",1,[629,634,636],{"class":635},"sMK4o","class",[629,638,640],{"class":639},"sBMFI"," ProfileScreen",[629,642,643],{"class":635}," extends",[629,645,646],{"class":639}," HookWidget",[629,648,650],{"class":649},"sTEyZ"," {\n",[629,652,654,658,661,664],{"class":631,"line":653},2,[629,655,657],{"class":656},"spNyl","  final",[629,659,660],{"class":639}," String",[629,662,663],{"class":649}," userId",[629,665,666],{"class":635},";\n",[629,668,670,673,675,678,681,684,687,690,693,695,698],{"class":631,"line":669},3,[629,671,672],{"class":656},"  const",[629,674,640],{"class":639},[629,676,677],{"class":649},"({super",[629,679,680],{"class":635},".",[629,682,683],{"class":649},"key",[629,685,686],{"class":635},",",[629,688,689],{"class":656}," required",[629,691,692],{"class":649}," this",[629,694,680],{"class":635},[629,696,697],{"class":649},"userId})",[629,699,666],{"class":635},[629,701,703],{"class":631,"line":702},4,[629,704,706],{"emptyLinePlaceholder":705},true,"\n",[629,708,710],{"class":631,"line":709},5,[629,711,712],{"class":656},"  @override\n",[629,714,716,719,723,726,729],{"class":631,"line":715},6,[629,717,718],{"class":639},"  Widget",[629,720,722],{"class":721},"s2Zo4"," build",[629,724,725],{"class":649},"(",[629,727,728],{"class":639},"BuildContext",[629,730,731],{"class":649}," context) {\n",[629,733,735],{"class":631,"line":734},7,[629,736,738],{"class":737},"sHwdD","    // ── Data ─────────────────────────────────────────────────────────────\n",[629,740,742,745,748,751,754,757],{"class":631,"line":741},8,[629,743,744],{"class":656},"    final",[629,746,747],{"class":649}," client   ",[629,749,750],{"class":635},"=",[629,752,753],{"class":721}," useQueryClient",[629,755,756],{"class":649},"()",[629,758,666],{"class":635},[629,760,762,764,767,769,772,775,778],{"class":631,"line":761},9,[629,763,744],{"class":656},[629,765,766],{"class":649}," userQuery ",[629,768,750],{"class":635},[629,770,771],{"class":721}," useQuery",[629,773,774],{"class":649},"\u003C",[629,776,777],{"class":639},"User",[629,779,780],{"class":649},">(\n",[629,782,784,787,789,792,796,798,801],{"class":631,"line":783},10,[629,785,786],{"class":649},"      key",[629,788,619],{"class":635},[629,790,791],{"class":649}," [",[629,793,795],{"class":794},"sfazB","'users'",[629,797,686],{"class":635},[629,799,800],{"class":649}," userId]",[629,802,803],{"class":635},",\n",[629,805,807,810,812,815,818,821,823,826,829],{"class":631,"line":806},11,[629,808,809],{"class":649},"      fetcher",[629,811,619],{"class":635},[629,813,814],{"class":649}," () ",[629,816,817],{"class":635},"=>",[629,819,820],{"class":639}," Api",[629,822,680],{"class":635},[629,824,825],{"class":721},"getUser",[629,827,828],{"class":649},"(userId)",[629,830,803],{"class":635},[629,832,834,837,839,842,845,848,850,853,856,858,862,865],{"class":631,"line":833},12,[629,835,836],{"class":649},"      options",[629,838,619],{"class":635},[629,840,841],{"class":656}," const",[629,843,844],{"class":639}," QoraOptions",[629,846,847],{"class":649},"(staleTime",[629,849,619],{"class":635},[629,851,852],{"class":639}," Duration",[629,854,855],{"class":649},"(minutes",[629,857,619],{"class":635},[629,859,861],{"class":860},"sbssI"," 5",[629,863,864],{"class":649},"))",[629,866,803],{"class":635},[629,868,870,873],{"class":631,"line":869},13,[629,871,872],{"class":649},"    )",[629,874,666],{"class":635},[629,876,878,880,883,885,888,890,892,894,897],{"class":631,"line":877},14,[629,879,744],{"class":656},[629,881,882],{"class":649}," updateMutation ",[629,884,750],{"class":635},[629,886,887],{"class":721}," useMutation",[629,889,774],{"class":649},[629,891,777],{"class":639},[629,893,420],{"class":649},[629,895,896],{"class":639},"UpdateUserInput",[629,898,780],{"class":649},[629,900,902,905,907,909,911,914],{"class":631,"line":901},15,[629,903,904],{"class":649},"      mutator",[629,906,619],{"class":635},[629,908,820],{"class":639},[629,910,680],{"class":635},[629,912,913],{"class":649},"updateUser",[629,915,803],{"class":635},[629,917,919,921,923,926],{"class":631,"line":918},16,[629,920,836],{"class":649},[629,922,619],{"class":635},[629,924,925],{"class":639}," MutationOptions",[629,927,928],{"class":649},"(\n",[629,930,932,935,937,940,942,945,947,950,954],{"class":631,"line":931},17,[629,933,934],{"class":649},"        onSuccess",[629,936,619],{"class":635},[629,938,939],{"class":649}," (user",[629,941,686],{"class":635},[629,943,944],{"class":649}," _",[629,946,686],{"class":635},[629,948,949],{"class":649}," __) ",[629,951,953],{"class":952},"s7zQu","async",[629,955,956],{"class":635}," =>\n",[629,958,960,963,965,967,970,972,974,977],{"class":631,"line":959},18,[629,961,962],{"class":649},"            client",[629,964,680],{"class":635},[629,966,472],{"class":721},[629,968,969],{"class":649},"([",[629,971,795],{"class":794},[629,973,686],{"class":635},[629,975,976],{"class":649}," userId])",[629,978,803],{"class":635},[629,980,982,985],{"class":631,"line":981},19,[629,983,984],{"class":649},"      )",[629,986,803],{"class":635},[629,988,990,992],{"class":631,"line":989},20,[629,991,872],{"class":649},[629,993,666],{"class":635},[629,995,997],{"class":631,"line":996},21,[629,998,706],{"emptyLinePlaceholder":705},[629,1000,1002],{"class":631,"line":1001},22,[629,1003,1004],{"class":737},"    // ── UI ───────────────────────────────────────────────────────────────\n",[629,1006,1008,1011,1014],{"class":631,"line":1007},23,[629,1009,1010],{"class":952},"    return",[629,1012,1013],{"class":639}," Scaffold",[629,1015,928],{"class":649},[629,1017,1019,1022,1024,1027],{"class":631,"line":1018},24,[629,1020,1021],{"class":649},"      appBar",[629,1023,619],{"class":635},[629,1025,1026],{"class":639}," AppBar",[629,1028,928],{"class":649},[629,1030,1032,1035,1037,1039,1042,1044,1047,1049],{"class":631,"line":1031},25,[629,1033,1034],{"class":649},"        title",[629,1036,619],{"class":635},[629,1038,841],{"class":656},[629,1040,1041],{"class":639}," Text",[629,1043,725],{"class":649},[629,1045,1046],{"class":794},"'Profile'",[629,1048,476],{"class":649},[629,1050,803],{"class":635},[629,1052,1054,1057,1059],{"class":631,"line":1053},26,[629,1055,1056],{"class":649},"        actions",[629,1058,619],{"class":635},[629,1060,1061],{"class":649}," [\n",[629,1063,1065,1068,1071,1073],{"class":631,"line":1064},27,[629,1066,1067],{"class":952},"          if",[629,1069,1070],{"class":649}," (updateMutation",[629,1072,680],{"class":635},[629,1074,1075],{"class":649},"isError)\n",[629,1077,1079,1082],{"class":631,"line":1078},28,[629,1080,1081],{"class":639},"            IconButton",[629,1083,928],{"class":649},[629,1085,1087,1090,1092,1094,1097,1099,1102,1104,1107,1109,1112,1114,1117,1119,1122],{"class":631,"line":1086},29,[629,1088,1089],{"class":649},"              icon",[629,1091,619],{"class":635},[629,1093,841],{"class":656},[629,1095,1096],{"class":639}," Icon",[629,1098,725],{"class":649},[629,1100,1101],{"class":639},"Icons",[629,1103,680],{"class":635},[629,1105,1106],{"class":649},"warning_amber",[629,1108,686],{"class":635},[629,1110,1111],{"class":649}," color",[629,1113,619],{"class":635},[629,1115,1116],{"class":639}," Colors",[629,1118,680],{"class":635},[629,1120,1121],{"class":649},"orange)",[629,1123,803],{"class":635},[629,1125,1127,1130,1132,1135],{"class":631,"line":1126},30,[629,1128,1129],{"class":649},"              tooltip",[629,1131,619],{"class":635},[629,1133,1134],{"class":794}," 'Save failed: tap to retry'",[629,1136,803],{"class":635},[629,1138,1140,1143,1145,1148,1150,1152],{"class":631,"line":1139},31,[629,1141,1142],{"class":649},"              onPressed",[629,1144,619],{"class":635},[629,1146,1147],{"class":649}," updateMutation",[629,1149,680],{"class":635},[629,1151,435],{"class":649},[629,1153,803],{"class":635},[629,1155,1157,1160],{"class":631,"line":1156},32,[629,1158,1159],{"class":649},"            )",[629,1161,803],{"class":635},[629,1163,1165,1168],{"class":631,"line":1164},33,[629,1166,1167],{"class":649},"        ]",[629,1169,803],{"class":635},[629,1171,1173,1175],{"class":631,"line":1172},34,[629,1174,984],{"class":649},[629,1176,803],{"class":635},[629,1178,1180,1183,1185,1188],{"class":631,"line":1179},35,[629,1181,1182],{"class":649},"      body",[629,1184,619],{"class":635},[629,1186,1187],{"class":952}," switch",[629,1189,1190],{"class":649}," (userQuery) {\n",[629,1192,1194,1197,1200,1203,1206,1209,1211,1214,1217],{"class":631,"line":1193},36,[629,1195,1196],{"class":639},"        Initial",[629,1198,1199],{"class":649},"() ",[629,1201,1202],{"class":635},"||",[629,1204,1205],{"class":639}," Loading",[629,1207,1208],{"class":649},"(previousData",[629,1210,619],{"class":635},[629,1212,1213],{"class":635}," null",[629,1215,1216],{"class":649},") ",[629,1218,1219],{"class":635},"=>\n",[629,1221,1223,1226,1229,1232,1234,1237,1240],{"class":631,"line":1222},37,[629,1224,1225],{"class":656},"            const",[629,1227,1228],{"class":639}," Center",[629,1230,1231],{"class":649},"(child",[629,1233,619],{"class":635},[629,1235,1236],{"class":639}," CircularProgressIndicator",[629,1238,1239],{"class":649},"())",[629,1241,803],{"class":635},[629,1243,1245,1248,1250,1252,1255,1258,1260,1263,1265,1267,1269,1271,1274,1277],{"class":631,"line":1244},38,[629,1246,1247],{"class":639},"        Failure",[629,1249,725],{"class":649},[629,1251,619],{"class":635},[629,1253,1254],{"class":656},"final",[629,1256,1257],{"class":649}," error",[629,1259,686],{"class":635},[629,1261,1262],{"class":649}," previousData",[629,1264,619],{"class":635},[629,1266,1213],{"class":635},[629,1268,1216],{"class":649},[629,1270,817],{"class":635},[629,1272,1273],{"class":639}," ErrorScreen",[629,1275,1276],{"class":649},"(error)",[629,1278,803],{"class":635},[629,1280,1282,1285,1287,1290],{"class":631,"line":1281},39,[629,1283,1284],{"class":649},"        _ ",[629,1286,817],{"class":635},[629,1288,1289],{"class":639}," ProfileForm",[629,1291,928],{"class":649},[629,1293,1295,1298,1300,1303,1305,1308],{"class":631,"line":1294},40,[629,1296,1297],{"class":649},"            user",[629,1299,619],{"class":635},[629,1301,1302],{"class":649},"        userQuery",[629,1304,680],{"class":635},[629,1306,1307],{"class":649},"dataOrNull",[629,1309,1310],{"class":635},"!,\n",[629,1312,1314,1317,1319,1322,1324,1326],{"class":631,"line":1313},41,[629,1315,1316],{"class":649},"            isSaving",[629,1318,619],{"class":635},[629,1320,1321],{"class":649},"    updateMutation",[629,1323,680],{"class":635},[629,1325,426],{"class":649},[629,1327,803],{"class":635},[629,1329,1331,1334,1336,1339,1341,1344],{"class":631,"line":1330},42,[629,1332,1333],{"class":649},"            saveError",[629,1335,619],{"class":635},[629,1337,1338],{"class":649},"   updateMutation",[629,1340,680],{"class":635},[629,1342,1343],{"class":649},"error",[629,1345,803],{"class":635},[629,1347,1349,1352,1354,1357,1359,1361,1363,1365,1368],{"class":631,"line":1348},43,[629,1350,1351],{"class":649},"            onSave",[629,1353,619],{"class":635},[629,1355,1356],{"class":649}," (input) ",[629,1358,817],{"class":635},[629,1360,1147],{"class":649},[629,1362,680],{"class":635},[629,1364,419],{"class":721},[629,1366,1367],{"class":649},"(input)",[629,1369,803],{"class":635},[629,1371,1373,1376],{"class":631,"line":1372},44,[629,1374,1375],{"class":649},"          )",[629,1377,803],{"class":635},[629,1379,1381,1384],{"class":631,"line":1380},45,[629,1382,1383],{"class":649},"      }",[629,1385,803],{"class":635},[629,1387,1389,1391],{"class":631,"line":1388},46,[629,1390,872],{"class":649},[629,1392,666],{"class":635},[629,1394,1396],{"class":631,"line":1395},47,[629,1397,1398],{"class":649},"  }\n",[629,1400,1402],{"class":631,"line":1401},48,[629,1403,1404],{"class":649},"}\n",[353,1406,1407,1408,607,1410,1412,1413,1416,1417,1420],{},"The equivalent using ",[361,1409,108],{},[361,1411,113],{}," would require two nested ",[361,1414,1415],{},"builder"," callbacks and a ",[361,1418,1419],{},"Stack"," to overlay the save state: roughly 2× the line count with the same logic.",[596,1422,1424,1426],{"id":1423},"usequery-is-synchronous-on-cache-hit",[361,1425,372],{}," is synchronous on cache hit",[353,1428,1429,1430,619],{},"The key implementation detail in ",[361,1431,1432],{},"use_query.dart",[559,1434,1436],{"className":622,"code":1435,"language":625,"meta":565,"style":565},"// Initialise from cache: avoids a loading flash when data is already fresh.\nfinal state = useState\u003CQoraState\u003CT>>(client.getQueryState\u003CT>(key));\n",[361,1437,1438,1443],{"__ignoreMap":565},[629,1439,1440],{"class":631,"line":632},[629,1441,1442],{"class":737},"// Initialise from cache: avoids a loading flash when data is already fresh.\n",[629,1444,1445,1447,1450,1452,1455,1457,1459,1461,1464,1467,1469,1472,1474,1476,1479],{"class":631,"line":653},[629,1446,1254],{"class":656},[629,1448,1449],{"class":649}," state ",[629,1451,750],{"class":635},[629,1453,1454],{"class":721}," useState",[629,1456,774],{"class":649},[629,1458,211],{"class":639},[629,1460,774],{"class":649},[629,1462,1463],{"class":639},"T",[629,1465,1466],{"class":649},">>(client",[629,1468,680],{"class":635},[629,1470,1471],{"class":721},"getQueryState",[629,1473,774],{"class":649},[629,1475,1463],{"class":639},[629,1477,1478],{"class":649},">(key))",[629,1480,666],{"class":635},[353,1482,1483,1485,1486,1489,1490,416,1493,420,1496,1498,1499,1502,1503,1506,1507,1510,1511,1514,1515,1517,1518,1520],{},[361,1484,1471],{}," is a ",[356,1487,1488],{},"synchronous"," read of the current cache entry. If another widget already fetched ",[361,1491,1492],{},"['users', userId]",[361,1494,1495],{},"staleTime: 5 minutes",[361,1497,372],{}," returns ",[361,1500,1501],{},"Success(data: user)"," on the ",[356,1504,1505],{},"first frame",": no ",[361,1508,1509],{},"Initial"," flash, no ",[361,1512,1513],{},"Loading"," state. This is identical to how ",[361,1516,108],{}," uses ",[361,1519,537],{}," (which also reads the current value synchronously before the stream starts).",[596,1522,1524,1526],{"id":1523},"useisfetching-global-progress-bar-without-coupling",[361,1525,483],{},": global progress bar without coupling",[353,1528,1529,1530,1532,1533,1537],{},"A common UX requirement: show a thin ",[361,1531,494],{}," at the top of the app whenever ",[1534,1535,1536],"em",{},"any"," query is loading. With hooks, this is a one-liner in any widget, with zero knowledge of specific queries:",[559,1539,1542],{"className":622,"code":1540,"filename":1541,"language":625,"meta":565,"style":565},"class AppProgressBar extends HookWidget {\n  const AppProgressBar({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    final isFetching = useIsFetching(); // true if ANY query has a request in flight\n\n    return AnimatedOpacity(\n      opacity: isFetching ? 1.0 : 0.0,\n      duration: const Duration(milliseconds: 250),\n      child: const LinearProgressIndicator(minHeight: 2),\n    );\n  }\n}\n","lib/shared/widgets/app_progress_bar.dart",[361,1543,1544,1557,1572,1576,1580,1592,1612,1616,1625,1648,1671,1695,1701,1705],{"__ignoreMap":565},[629,1545,1546,1548,1551,1553,1555],{"class":631,"line":632},[629,1547,636],{"class":635},[629,1549,1550],{"class":639}," AppProgressBar",[629,1552,643],{"class":635},[629,1554,646],{"class":639},[629,1556,650],{"class":649},[629,1558,1559,1561,1563,1565,1567,1570],{"class":631,"line":653},[629,1560,672],{"class":656},[629,1562,1550],{"class":639},[629,1564,677],{"class":649},[629,1566,680],{"class":635},[629,1568,1569],{"class":649},"key})",[629,1571,666],{"class":635},[629,1573,1574],{"class":631,"line":669},[629,1575,706],{"emptyLinePlaceholder":705},[629,1577,1578],{"class":631,"line":702},[629,1579,712],{"class":656},[629,1581,1582,1584,1586,1588,1590],{"class":631,"line":709},[629,1583,718],{"class":639},[629,1585,722],{"class":721},[629,1587,725],{"class":649},[629,1589,728],{"class":639},[629,1591,731],{"class":649},[629,1593,1594,1596,1599,1601,1604,1606,1609],{"class":631,"line":715},[629,1595,744],{"class":656},[629,1597,1598],{"class":649}," isFetching ",[629,1600,750],{"class":635},[629,1602,1603],{"class":721}," useIsFetching",[629,1605,756],{"class":649},[629,1607,1608],{"class":635},";",[629,1610,1611],{"class":737}," // true if ANY query has a request in flight\n",[629,1613,1614],{"class":631,"line":734},[629,1615,706],{"emptyLinePlaceholder":705},[629,1617,1618,1620,1623],{"class":631,"line":741},[629,1619,1010],{"class":952},[629,1621,1622],{"class":639}," AnimatedOpacity",[629,1624,928],{"class":649},[629,1626,1627,1630,1632,1634,1637,1640,1643,1646],{"class":631,"line":761},[629,1628,1629],{"class":649},"      opacity",[629,1631,619],{"class":635},[629,1633,1598],{"class":649},[629,1635,1636],{"class":635},"?",[629,1638,1639],{"class":860}," 1.0",[629,1641,1642],{"class":635}," :",[629,1644,1645],{"class":860}," 0.0",[629,1647,803],{"class":635},[629,1649,1650,1653,1655,1657,1659,1662,1664,1667,1669],{"class":631,"line":783},[629,1651,1652],{"class":649},"      duration",[629,1654,619],{"class":635},[629,1656,841],{"class":656},[629,1658,852],{"class":639},[629,1660,1661],{"class":649},"(milliseconds",[629,1663,619],{"class":635},[629,1665,1666],{"class":860}," 250",[629,1668,476],{"class":649},[629,1670,803],{"class":635},[629,1672,1673,1676,1678,1680,1683,1686,1688,1691,1693],{"class":631,"line":806},[629,1674,1675],{"class":649},"      child",[629,1677,619],{"class":635},[629,1679,841],{"class":656},[629,1681,1682],{"class":639}," LinearProgressIndicator",[629,1684,1685],{"class":649},"(minHeight",[629,1687,619],{"class":635},[629,1689,1690],{"class":860}," 2",[629,1692,476],{"class":649},[629,1694,803],{"class":635},[629,1696,1697,1699],{"class":631,"line":833},[629,1698,872],{"class":649},[629,1700,666],{"class":635},[629,1702,1703],{"class":631,"line":869},[629,1704,1398],{"class":649},[629,1706,1707],{"class":631,"line":877},[629,1708,1404],{"class":649},[353,1710,1711,1713,1714,1717,1718,1720,1721,1724,1725,1728],{},[361,1712,483],{}," only rebuilds when the value ",[356,1715,1716],{},"crosses zero",": not on every count change. If 5 queries are running and one finishes, the widget does not rebuild (still ",[361,1719,490],{},"). It rebuilds only when the last query finishes (",[361,1722,1723],{},"true → false",") or when the first starts (",[361,1726,1727],{},"false → true",").",[596,1730,1732,1735],{"id":1731},"useinfinitequery-infinite-scroll-without-an-observer",[361,1733,1734],{},"useInfiniteQuery",": infinite scroll without an observer",[353,1737,1738,1739,1742,1743,1745],{},"The hooks API wraps ",[361,1740,1741],{},"InfiniteQueryObserver"," into a ",[361,1744,446],{}," with a flat interface:",[559,1747,1750],{"className":622,"code":1748,"filename":1749,"language":625,"meta":565,"style":565},"class PostsScreen extends HookWidget {\n  @override\n  Widget build(BuildContext context) {\n    final query = useInfiniteQuery\u003CPostsPage, String?>(\n      key: const ['posts'],\n      fetcher: (cursor) => Api.getPosts(cursor: cursor),\n      getNextPageParam: (page) => page.nextCursor,\n      initialPageParam: null,\n    );\n\n    if (query.isLoading) return const Center(child: CircularProgressIndicator());\n    if (query.error != null && query.pages.isEmpty) return ErrorScreen(query.error!);\n\n    final posts = query.pages.expand((p) => p.posts).toList();\n\n    return ListView.builder(\n      itemCount: posts.length + (query.hasNextPage ? 1 : 0),\n      itemBuilder: (context, i) {\n        if (i == posts.length) {\n          // Auto-trigger next page when the sentinel item is built\n          if (!query.isFetchingNextPage) query.fetchNextPage();\n          return const Center(child: CircularProgressIndicator());\n        }\n        return PostTile(posts[i]);\n      },\n    );\n  }\n}\n","lib/features/posts/ui/posts_screen.dart",[361,1751,1752,1765,1769,1781,1806,1824,1852,1874,1884,1890,1894,1924,1973,1977,2019,2023,2036,2075,2090,2108,2113,2138,2157,2162,2175,2181,2187,2191],{"__ignoreMap":565},[629,1753,1754,1756,1759,1761,1763],{"class":631,"line":632},[629,1755,636],{"class":635},[629,1757,1758],{"class":639}," PostsScreen",[629,1760,643],{"class":635},[629,1762,646],{"class":639},[629,1764,650],{"class":649},[629,1766,1767],{"class":631,"line":653},[629,1768,712],{"class":656},[629,1770,1771,1773,1775,1777,1779],{"class":631,"line":669},[629,1772,718],{"class":639},[629,1774,722],{"class":721},[629,1776,725],{"class":649},[629,1778,728],{"class":639},[629,1780,731],{"class":649},[629,1782,1783,1785,1788,1790,1793,1795,1798,1800,1803],{"class":631,"line":702},[629,1784,744],{"class":656},[629,1786,1787],{"class":649}," query ",[629,1789,750],{"class":635},[629,1791,1792],{"class":721}," useInfiniteQuery",[629,1794,774],{"class":649},[629,1796,1797],{"class":639},"PostsPage",[629,1799,420],{"class":649},[629,1801,1802],{"class":639},"String",[629,1804,1805],{"class":649},"?>(\n",[629,1807,1808,1810,1812,1814,1816,1819,1822],{"class":631,"line":709},[629,1809,786],{"class":649},[629,1811,619],{"class":635},[629,1813,841],{"class":656},[629,1815,791],{"class":649},[629,1817,1818],{"class":794},"'posts'",[629,1820,1821],{"class":649},"]",[629,1823,803],{"class":635},[629,1825,1826,1828,1830,1833,1835,1837,1839,1842,1845,1847,1850],{"class":631,"line":715},[629,1827,809],{"class":649},[629,1829,619],{"class":635},[629,1831,1832],{"class":649}," (cursor) ",[629,1834,817],{"class":635},[629,1836,820],{"class":639},[629,1838,680],{"class":635},[629,1840,1841],{"class":721},"getPosts",[629,1843,1844],{"class":649},"(cursor",[629,1846,619],{"class":635},[629,1848,1849],{"class":649}," cursor)",[629,1851,803],{"class":635},[629,1853,1854,1857,1859,1862,1864,1867,1869,1872],{"class":631,"line":734},[629,1855,1856],{"class":649},"      getNextPageParam",[629,1858,619],{"class":635},[629,1860,1861],{"class":649}," (page) ",[629,1863,817],{"class":635},[629,1865,1866],{"class":649}," page",[629,1868,680],{"class":635},[629,1870,1871],{"class":649},"nextCursor",[629,1873,803],{"class":635},[629,1875,1876,1879,1881],{"class":631,"line":741},[629,1877,1878],{"class":649},"      initialPageParam",[629,1880,619],{"class":635},[629,1882,1883],{"class":635}," null,\n",[629,1885,1886,1888],{"class":631,"line":761},[629,1887,872],{"class":649},[629,1889,666],{"class":635},[629,1891,1892],{"class":631,"line":783},[629,1893,706],{"emptyLinePlaceholder":705},[629,1895,1896,1899,1902,1904,1907,1910,1912,1914,1916,1918,1920,1922],{"class":631,"line":806},[629,1897,1898],{"class":952},"    if",[629,1900,1901],{"class":649}," (query",[629,1903,680],{"class":635},[629,1905,1906],{"class":649},"isLoading) ",[629,1908,1909],{"class":952},"return",[629,1911,841],{"class":656},[629,1913,1228],{"class":639},[629,1915,1231],{"class":649},[629,1917,619],{"class":635},[629,1919,1236],{"class":639},[629,1921,1239],{"class":649},[629,1923,666],{"class":635},[629,1925,1926,1928,1930,1932,1935,1938,1940,1943,1946,1948,1950,1952,1955,1957,1959,1962,1964,1966,1969,1971],{"class":631,"line":833},[629,1927,1898],{"class":952},[629,1929,1901],{"class":649},[629,1931,680],{"class":635},[629,1933,1934],{"class":649},"error ",[629,1936,1937],{"class":635},"!=",[629,1939,1213],{"class":635},[629,1941,1942],{"class":635}," &&",[629,1944,1945],{"class":649}," query",[629,1947,680],{"class":635},[629,1949,449],{"class":649},[629,1951,680],{"class":635},[629,1953,1954],{"class":649},"isEmpty) ",[629,1956,1909],{"class":952},[629,1958,1273],{"class":639},[629,1960,1961],{"class":649},"(query",[629,1963,680],{"class":635},[629,1965,1343],{"class":649},[629,1967,1968],{"class":635},"!",[629,1970,476],{"class":649},[629,1972,666],{"class":635},[629,1974,1975],{"class":631,"line":869},[629,1976,706],{"emptyLinePlaceholder":705},[629,1978,1979,1981,1984,1986,1988,1990,1992,1994,1997,2000,2002,2005,2007,2010,2012,2015,2017],{"class":631,"line":877},[629,1980,744],{"class":656},[629,1982,1983],{"class":649}," posts ",[629,1985,750],{"class":635},[629,1987,1945],{"class":649},[629,1989,680],{"class":635},[629,1991,449],{"class":649},[629,1993,680],{"class":635},[629,1995,1996],{"class":721},"expand",[629,1998,1999],{"class":649},"((p) ",[629,2001,817],{"class":635},[629,2003,2004],{"class":649}," p",[629,2006,680],{"class":635},[629,2008,2009],{"class":649},"posts)",[629,2011,680],{"class":635},[629,2013,2014],{"class":721},"toList",[629,2016,756],{"class":649},[629,2018,666],{"class":635},[629,2020,2021],{"class":631,"line":901},[629,2022,706],{"emptyLinePlaceholder":705},[629,2024,2025,2027,2030,2032,2034],{"class":631,"line":918},[629,2026,1010],{"class":952},[629,2028,2029],{"class":639}," ListView",[629,2031,680],{"class":635},[629,2033,1415],{"class":721},[629,2035,928],{"class":649},[629,2037,2038,2041,2043,2046,2048,2051,2054,2056,2058,2061,2063,2066,2068,2071,2073],{"class":631,"line":931},[629,2039,2040],{"class":649},"      itemCount",[629,2042,619],{"class":635},[629,2044,2045],{"class":649}," posts",[629,2047,680],{"class":635},[629,2049,2050],{"class":649},"length ",[629,2052,2053],{"class":635},"+",[629,2055,1901],{"class":649},[629,2057,680],{"class":635},[629,2059,2060],{"class":649},"hasNextPage ",[629,2062,1636],{"class":635},[629,2064,2065],{"class":860}," 1",[629,2067,1642],{"class":635},[629,2069,2070],{"class":860}," 0",[629,2072,476],{"class":649},[629,2074,803],{"class":635},[629,2076,2077,2080,2082,2085,2087],{"class":631,"line":959},[629,2078,2079],{"class":649},"      itemBuilder",[629,2081,619],{"class":635},[629,2083,2084],{"class":649}," (context",[629,2086,686],{"class":635},[629,2088,2089],{"class":649}," i) {\n",[629,2091,2092,2095,2098,2101,2103,2105],{"class":631,"line":981},[629,2093,2094],{"class":952},"        if",[629,2096,2097],{"class":649}," (i ",[629,2099,2100],{"class":635},"==",[629,2102,2045],{"class":649},[629,2104,680],{"class":635},[629,2106,2107],{"class":649},"length) {\n",[629,2109,2110],{"class":631,"line":989},[629,2111,2112],{"class":737},"          // Auto-trigger next page when the sentinel item is built\n",[629,2114,2115,2117,2120,2122,2125,2127,2130,2132,2134,2136],{"class":631,"line":996},[629,2116,1067],{"class":952},[629,2118,2119],{"class":649}," (",[629,2121,1968],{"class":635},[629,2123,2124],{"class":649},"query",[629,2126,680],{"class":635},[629,2128,2129],{"class":649},"isFetchingNextPage) query",[629,2131,680],{"class":635},[629,2133,452],{"class":721},[629,2135,756],{"class":649},[629,2137,666],{"class":635},[629,2139,2140,2143,2145,2147,2149,2151,2153,2155],{"class":631,"line":1001},[629,2141,2142],{"class":952},"          return",[629,2144,841],{"class":656},[629,2146,1228],{"class":639},[629,2148,1231],{"class":649},[629,2150,619],{"class":635},[629,2152,1236],{"class":639},[629,2154,1239],{"class":649},[629,2156,666],{"class":635},[629,2158,2159],{"class":631,"line":1007},[629,2160,2161],{"class":649},"        }\n",[629,2163,2164,2167,2170,2173],{"class":631,"line":1018},[629,2165,2166],{"class":952},"        return",[629,2168,2169],{"class":639}," PostTile",[629,2171,2172],{"class":649},"(posts[i])",[629,2174,666],{"class":635},[629,2176,2177,2179],{"class":631,"line":1031},[629,2178,1383],{"class":649},[629,2180,803],{"class":635},[629,2182,2183,2185],{"class":631,"line":1053},[629,2184,872],{"class":649},[629,2186,666],{"class":635},[629,2188,2189],{"class":631,"line":1064},[629,2190,1398],{"class":649},[629,2192,2193],{"class":631,"line":1078},[629,2194,1404],{"class":649},[353,2196,2197,2198,2201],{},"No explicit ",[361,2199,2200],{},"dispose"," is required: the observer is tied to the hook's lifecycle and cleaned up automatically when the widget unmounts.",[383,2203],{},[348,2205,2207],{"id":2206},"source-code","Source Code",[559,2209,2212],{"className":2210,"code":2211,"language":564,"meta":565},[562],"examples/ex_06_hooks_integration/\n├── lib/\n│   ├── main.dart                          ← QoraClient + QoraScope setup\n│   ├── shared/\n│   │   ├── api/json_placeholder_api.dart  ← shared JSONPlaceholder client\n│   │   └── widgets/\n│   │       └── app_progress_bar.dart      ← useIsFetching global indicator\n│   └── features/\n│       ├── profile/\n│       │   ├── models/user.dart           ← User model\n│       │   └── ui/profile_screen.dart     ← useQuery + useMutation composition\n│       └── posts/\n│           ├── models/posts_page.dart     ← PostsPage model\n│           └── ui/posts_screen.dart       ← useInfiniteQuery\n└── pubspec.yaml\n",[361,2213,2211],{"__ignoreMap":565},[353,2215,2216],{},[2217,2218,2222],"a",{"href":2219,"rel":2220},"https://github.com/meragix/qora/tree/main/examples/ex_06_hooks_integration",[2221],"nofollow","View full source code",[383,2224],{},[348,2226,2228],{"id":2227},"when-to-use-hooks-vs-builders","When to use hooks vs builders",[2230,2231,2232,2245],"table",{},[2233,2234,2235],"thead",{},[2236,2237,2238,2242],"tr",{},[2239,2240,2241],"th",{},"Situation",[2239,2243,2244],{},"Prefer",[2246,2247,2248,2259,2271,2284,2298],"tbody",{},[2236,2249,2250,2254],{},[2251,2252,2253],"td",{},"Single query, simple screen",[2251,2255,2256,2258],{},[361,2257,108],{}," or hooks",[2236,2260,2261,2264],{},[2251,2262,2263],{},"Query + mutation on same screen",[2251,2265,2266,607,2268,2270],{},[361,2267,372],{},[361,2269,376],{},": eliminates nesting",[2236,2272,2273,2276],{},[2251,2274,2275],{},"Global loading/mutating indicator",[2251,2277,2278,2280,2281,2283],{},[361,2279,483],{}," / ",[361,2282,502],{},": impossible to do cleanly with builders",[2236,2285,2286,2293],{},[2251,2287,2288,2289,2292],{},"Already using ",[361,2290,2291],{},"flutter_hooks"," in the project",[2251,2294,2295,2297],{},[361,2296,368],{},": consistent style across the codebase",[2236,2299,2300,2307],{},[2251,2301,2302,2280,2304,2306],{},[361,2303,581],{},[361,2305,584],{}," codebase",[2251,2308,2309,2280,2311,2313,2314],{},[361,2310,108],{},[361,2312,113],{},": hooks require ",[361,2315,573],{},[383,2317],{},[348,2319,2321],{"id":2320},"related","Related",[390,2323,2324,2331,2339,2350],{},[393,2325,2326,2330],{},[2217,2327,2329],{"href":2328},"../flutter-integration/hooks","Hooks Reference",": full API for all hooks",[393,2332,2333,2336,2337],{},[2217,2334,108],{"href":2335},"../flutter-integration/qora-builder",": widget alternative to ",[361,2338,372],{},[393,2340,2341,359,2345,373,2347,2349],{},[2217,2342,2344],{"href":2343},"../recipes/mutations","Mutations Recipe",[361,2346,376],{},[361,2348,113],{}," patterns",[393,2351,2352,359,2356,2358],{},[2217,2353,2355],{"href":2354},"./infinite-scroll","Infinite Scroll Case Study",[361,2357,1734],{}," in a production feed",[2360,2361,2362],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":565,"searchDepth":653,"depth":653,"links":2364},[2365,2366,2367,2368,2378,2379,2380],{"id":350,"depth":653,"text":351},{"id":387,"depth":653,"text":388},{"id":521,"depth":653,"text":522},{"id":593,"depth":653,"text":594,"children":2369},[2370,2372,2374,2376],{"id":598,"depth":669,"text":2371},"Hook composition: a complete screen in one build()",{"id":1423,"depth":669,"text":2373},"useQuery is synchronous on cache hit",{"id":1523,"depth":669,"text":2375},"useIsFetching: global progress bar without coupling",{"id":1731,"depth":669,"text":2377},"useInfiniteQuery: infinite scroll without an observer",{"id":2206,"depth":653,"text":2207},{"id":2227,"depth":653,"text":2228},{"id":2320,"depth":653,"text":2321},"Replace QoraBuilder widget nesting with flat, composable hook calls: useQuery, useMutation, useInfiniteQuery, and global fetch indicators in a HookWidget","md",null,{},{"icon":126},{"title":2387,"description":2388},"Case Study: Hooks Integration - Qora","Use qora_hooks with flutter_hooks to write server-state screens without StatefulWidget or StreamSubscription. useQuery, useMutation, useIsFetching, and hook composition.","S0dTZVM9ks8PH-ioD3jSRCDtR6kuIaCVkI0fGrzOtpc",[2391,2393],{"title":315,"path":316,"stem":317,"description":2392,"icon":161,"children":-1},"Queries pause automatically when offline, mutations queue for later, and everything replays on reconnect: with thundering-herd prevention built in.",{"title":323,"path":324,"stem":325,"description":2394,"icon":326,"children":-1},"A production-grade Flutter app combining every Qora capability: PersistQoraClient, infinite scroll with pagination, optimistic create/toggle/delete, offline mutation queue, and simulated connectivity toggling.",1794040403013]