[{"data":1,"prerenderedAt":1718},["ShallowReactive",2],{"navigation_docs_en":3,"-en-recipes-cancel-token":342,"-en-recipes-cancel-token-surround":1713},[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":172,"body":344,"description":1706,"extension":1707,"links":1708,"meta":1709,"navigation":1710,"path":173,"seo":1711,"stem":174,"__hash__":1712},"docs_en/en/04.recipes/08.cancel-token.md",{"type":345,"value":346,"toc":1688},"minimark",[347,371,374,379,416,422,424,430,689,699,701,707,855,867,869,873,883,1092,1094,1098,1105,1368,1370,1376,1381,1393,1397,1441,1445,1474,1476,1481,1492,1531,1562,1564,1568,1577,1653,1655,1659,1684],[348,349,350,354,355,358,359,362,363,366,367,370],"p",{},[351,352,353],"code",{},"CancelToken"," is a one-shot cooperative cancellation signal. Pass it to ",[351,356,357],{},"fetchQuery",", ",[351,360,361],{},"watchQuery",", or ",[351,364,365],{},"prefetch"," and call ",[351,368,369],{},"cancel()"," to abort the fetch before start or during execution.",[372,373],"hr",{},[375,376,378],"h2",{"id":377},"creating-a-token","Creating a Token",[380,381,387],"pre",{"className":382,"code":383,"filename":384,"language":385,"meta":386,"style":386},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","final token = CancelToken();\n","main.dart","dart","",[351,388,389],{"__ignoreMap":386},[390,391,394,398,402,406,410,413],"span",{"class":392,"line":393},"line",1,[390,395,397],{"class":396},"spNyl","final",[390,399,401],{"class":400},"sTEyZ"," token ",[390,403,405],{"class":404},"sMK4o","=",[390,407,409],{"class":408},"sBMFI"," CancelToken",[390,411,412],{"class":400},"()",[390,414,415],{"class":404},";\n",[348,417,418,419,421],{},"A token can only be cancelled once. Calling ",[351,420,369],{}," a second time is a no-op.",[372,423],{},[375,425,427,428],{"id":426},"cancelling-a-fetchquery","Cancelling a ",[351,429,357],{},[380,431,434],{"className":382,"code":432,"filename":433,"language":385,"meta":386,"style":386},"final token = CancelToken();\n\n// Start the fetch\nfinal future = client.fetchQuery\u003CUser>(\n  key: ['users', userId],\n  fetcher: () => api.getUser(userId),\n  cancelToken: token,\n);\n\n// Cancel it (e.g. the user navigated away)\ntoken.cancel();\n\ntry {\n  final user = await future;\n} on QoraCancelException catch (e) {\n  // e.key is the string-encoded query key\n  print('Fetch cancelled: ${e.key}');\n}\n","user_repository.dart",[351,435,436,450,457,464,492,517,544,557,565,570,576,591,596,606,625,643,649,683],{"__ignoreMap":386},[390,437,438,440,442,444,446,448],{"class":392,"line":393},[390,439,397],{"class":396},[390,441,401],{"class":400},[390,443,405],{"class":404},[390,445,409],{"class":408},[390,447,412],{"class":400},[390,449,415],{"class":404},[390,451,453],{"class":392,"line":452},2,[390,454,456],{"emptyLinePlaceholder":455},true,"\n",[390,458,460],{"class":392,"line":459},3,[390,461,463],{"class":462},"sHwdD","// Start the fetch\n",[390,465,467,469,472,474,477,480,483,486,489],{"class":392,"line":466},4,[390,468,397],{"class":396},[390,470,471],{"class":400}," future ",[390,473,405],{"class":404},[390,475,476],{"class":400}," client",[390,478,479],{"class":404},".",[390,481,357],{"class":482},"s2Zo4",[390,484,485],{"class":400},"\u003C",[390,487,488],{"class":408},"User",[390,490,491],{"class":400},">(\n",[390,493,495,498,501,504,508,511,514],{"class":392,"line":494},5,[390,496,497],{"class":400},"  key",[390,499,500],{"class":404},":",[390,502,503],{"class":400}," [",[390,505,507],{"class":506},"sfazB","'users'",[390,509,510],{"class":404},",",[390,512,513],{"class":400}," userId]",[390,515,516],{"class":404},",\n",[390,518,520,523,525,528,531,534,536,539,542],{"class":392,"line":519},6,[390,521,522],{"class":400},"  fetcher",[390,524,500],{"class":404},[390,526,527],{"class":400}," () ",[390,529,530],{"class":404},"=>",[390,532,533],{"class":400}," api",[390,535,479],{"class":404},[390,537,538],{"class":482},"getUser",[390,540,541],{"class":400},"(userId)",[390,543,516],{"class":404},[390,545,547,550,552,555],{"class":392,"line":546},7,[390,548,549],{"class":400},"  cancelToken",[390,551,500],{"class":404},[390,553,554],{"class":400}," token",[390,556,516],{"class":404},[390,558,560,563],{"class":392,"line":559},8,[390,561,562],{"class":400},")",[390,564,415],{"class":404},[390,566,568],{"class":392,"line":567},9,[390,569,456],{"emptyLinePlaceholder":455},[390,571,573],{"class":392,"line":572},10,[390,574,575],{"class":462},"// Cancel it (e.g. the user navigated away)\n",[390,577,579,582,584,587,589],{"class":392,"line":578},11,[390,580,581],{"class":400},"token",[390,583,479],{"class":404},[390,585,586],{"class":482},"cancel",[390,588,412],{"class":400},[390,590,415],{"class":404},[390,592,594],{"class":392,"line":593},12,[390,595,456],{"emptyLinePlaceholder":455},[390,597,599,603],{"class":392,"line":598},13,[390,600,602],{"class":601},"s7zQu","try",[390,604,605],{"class":400}," {\n",[390,607,609,612,615,617,620,623],{"class":392,"line":608},14,[390,610,611],{"class":396},"  final",[390,613,614],{"class":400}," user ",[390,616,405],{"class":404},[390,618,619],{"class":601}," await",[390,621,622],{"class":400}," future",[390,624,415],{"class":404},[390,626,628,631,634,637,640],{"class":392,"line":627},15,[390,629,630],{"class":400},"} ",[390,632,633],{"class":601},"on",[390,635,636],{"class":408}," QoraCancelException",[390,638,639],{"class":601}," catch",[390,641,642],{"class":400}," (e) {\n",[390,644,646],{"class":392,"line":645},16,[390,647,648],{"class":462},"  // e.key is the string-encoded query key\n",[390,650,652,655,658,661,664,668,670,673,676,679,681],{"class":392,"line":651},17,[390,653,654],{"class":482},"  print",[390,656,657],{"class":400},"(",[390,659,660],{"class":506},"'Fetch cancelled: ",[390,662,663],{"class":400},"${",[390,665,667],{"class":666},"sHdIc","e",[390,669,479],{"class":400},[390,671,672],{"class":666},"key",[390,674,675],{"class":400},"}",[390,677,678],{"class":506},"'",[390,680,562],{"class":400},[390,682,415],{"class":404},[390,684,686],{"class":392,"line":685},18,[390,687,688],{"class":400},"}\n",[348,690,691,692,694,695,698],{},"When cancelled, ",[351,693,357],{}," throws ",[351,696,697],{},"QoraCancelException"," to the caller and restores the cache entry to its pre-fetch snapshot (no partial state is left behind).",[372,700],{},[375,702,427,704,706],{"id":703},"cancelling-a-watchquery-stream",[351,705,361],{}," stream",[380,708,711],{"className":382,"code":709,"filename":710,"language":385,"meta":386,"style":386},"final token = CancelToken();\n\nfinal sub = client.watchQuery\u003CUser>(\n  key: ['users', userId],\n  fetcher: () => api.getUser(userId),\n  cancelToken: token,\n).listen((state) { ... });\n\n// On widget dispose: cancel the in-flight fetch\ntoken.cancel();\nawait sub.cancel();\n","user_page.dart",[351,712,713,727,731,752,768,788,798,818,822,827,839],{"__ignoreMap":386},[390,714,715,717,719,721,723,725],{"class":392,"line":393},[390,716,397],{"class":396},[390,718,401],{"class":400},[390,720,405],{"class":404},[390,722,409],{"class":408},[390,724,412],{"class":400},[390,726,415],{"class":404},[390,728,729],{"class":392,"line":452},[390,730,456],{"emptyLinePlaceholder":455},[390,732,733,735,738,740,742,744,746,748,750],{"class":392,"line":459},[390,734,397],{"class":396},[390,736,737],{"class":400}," sub ",[390,739,405],{"class":404},[390,741,476],{"class":400},[390,743,479],{"class":404},[390,745,361],{"class":482},[390,747,485],{"class":400},[390,749,488],{"class":408},[390,751,491],{"class":400},[390,753,754,756,758,760,762,764,766],{"class":392,"line":466},[390,755,497],{"class":400},[390,757,500],{"class":404},[390,759,503],{"class":400},[390,761,507],{"class":506},[390,763,510],{"class":404},[390,765,513],{"class":400},[390,767,516],{"class":404},[390,769,770,772,774,776,778,780,782,784,786],{"class":392,"line":494},[390,771,522],{"class":400},[390,773,500],{"class":404},[390,775,527],{"class":400},[390,777,530],{"class":404},[390,779,533],{"class":400},[390,781,479],{"class":404},[390,783,538],{"class":482},[390,785,541],{"class":400},[390,787,516],{"class":404},[390,789,790,792,794,796],{"class":392,"line":519},[390,791,549],{"class":400},[390,793,500],{"class":404},[390,795,554],{"class":400},[390,797,516],{"class":404},[390,799,800,802,804,807,810,813,816],{"class":392,"line":546},[390,801,562],{"class":400},[390,803,479],{"class":404},[390,805,806],{"class":482},"listen",[390,808,809],{"class":400},"((state) { ",[390,811,812],{"class":404},"...",[390,814,815],{"class":400}," })",[390,817,415],{"class":404},[390,819,820],{"class":392,"line":559},[390,821,456],{"emptyLinePlaceholder":455},[390,823,824],{"class":392,"line":567},[390,825,826],{"class":462},"// On widget dispose: cancel the in-flight fetch\n",[390,828,829,831,833,835,837],{"class":392,"line":572},[390,830,581],{"class":400},[390,832,479],{"class":404},[390,834,586],{"class":482},[390,836,412],{"class":400},[390,838,415],{"class":404},[390,840,841,844,847,849,851,853],{"class":392,"line":578},[390,842,843],{"class":601},"await",[390,845,846],{"class":400}," sub",[390,848,479],{"class":404},[390,850,586],{"class":482},[390,852,412],{"class":400},[390,854,415],{"class":404},[856,857,858,859,862,863,866],"tip",{},"Cancelling the stream subscription is separate from cancelling the fetch. ",[351,860,861],{},"token.cancel()"," aborts the HTTP request; ",[351,864,865],{},"sub.cancel()"," removes the state listener. Do both on dispose for a clean teardown.",[372,868],{},[375,870,872],{"id":871},"timeout-pattern","Timeout Pattern",[348,874,875,876,878,879,882],{},"Combine ",[351,877,353],{}," with ",[351,880,881],{},"Future.delayed"," to implement a request timeout:",[380,884,886],{"className":382,"code":885,"filename":433,"language":385,"meta":386,"style":386},"Future\u003CUser> fetchWithTimeout(int userId, Duration timeout) async {\n  final token = CancelToken();\n\n  Timer(timeout, token.cancel);\n\n  try {\n    return await client.fetchQuery\u003CUser>(\n      key: ['users', userId],\n      fetcher: () => api.getUser(userId),\n      cancelToken: token,\n    );\n  } on QoraCancelException {\n    throw TimeoutException('User fetch timed out after $timeout');\n  }\n}\n",[351,887,888,924,938,942,961,965,972,991,1008,1029,1040,1047,1058,1083,1088],{"__ignoreMap":386},[390,889,890,893,895,897,900,903,905,908,911,913,916,919,922],{"class":392,"line":393},[390,891,892],{"class":408},"Future",[390,894,485],{"class":400},[390,896,488],{"class":408},[390,898,899],{"class":400},"> ",[390,901,902],{"class":482},"fetchWithTimeout",[390,904,657],{"class":400},[390,906,907],{"class":408},"int",[390,909,910],{"class":400}," userId",[390,912,510],{"class":404},[390,914,915],{"class":408}," Duration",[390,917,918],{"class":400}," timeout) ",[390,920,921],{"class":601},"async",[390,923,605],{"class":400},[390,925,926,928,930,932,934,936],{"class":392,"line":452},[390,927,611],{"class":396},[390,929,401],{"class":400},[390,931,405],{"class":404},[390,933,409],{"class":408},[390,935,412],{"class":400},[390,937,415],{"class":404},[390,939,940],{"class":392,"line":459},[390,941,456],{"emptyLinePlaceholder":455},[390,943,944,947,950,952,954,956,959],{"class":392,"line":466},[390,945,946],{"class":408},"  Timer",[390,948,949],{"class":400},"(timeout",[390,951,510],{"class":404},[390,953,554],{"class":400},[390,955,479],{"class":404},[390,957,958],{"class":400},"cancel)",[390,960,415],{"class":404},[390,962,963],{"class":392,"line":494},[390,964,456],{"emptyLinePlaceholder":455},[390,966,967,970],{"class":392,"line":519},[390,968,969],{"class":601},"  try",[390,971,605],{"class":400},[390,973,974,977,979,981,983,985,987,989],{"class":392,"line":546},[390,975,976],{"class":601},"    return",[390,978,619],{"class":601},[390,980,476],{"class":400},[390,982,479],{"class":404},[390,984,357],{"class":482},[390,986,485],{"class":400},[390,988,488],{"class":408},[390,990,491],{"class":400},[390,992,993,996,998,1000,1002,1004,1006],{"class":392,"line":559},[390,994,995],{"class":400},"      key",[390,997,500],{"class":404},[390,999,503],{"class":400},[390,1001,507],{"class":506},[390,1003,510],{"class":404},[390,1005,513],{"class":400},[390,1007,516],{"class":404},[390,1009,1010,1013,1015,1017,1019,1021,1023,1025,1027],{"class":392,"line":567},[390,1011,1012],{"class":400},"      fetcher",[390,1014,500],{"class":404},[390,1016,527],{"class":400},[390,1018,530],{"class":404},[390,1020,533],{"class":400},[390,1022,479],{"class":404},[390,1024,538],{"class":482},[390,1026,541],{"class":400},[390,1028,516],{"class":404},[390,1030,1031,1034,1036,1038],{"class":392,"line":572},[390,1032,1033],{"class":400},"      cancelToken",[390,1035,500],{"class":404},[390,1037,554],{"class":400},[390,1039,516],{"class":404},[390,1041,1042,1045],{"class":392,"line":578},[390,1043,1044],{"class":400},"    )",[390,1046,415],{"class":404},[390,1048,1049,1052,1054,1056],{"class":392,"line":593},[390,1050,1051],{"class":400},"  } ",[390,1053,633],{"class":601},[390,1055,636],{"class":408},[390,1057,605],{"class":400},[390,1059,1060,1063,1066,1068,1071,1074,1077,1079,1081],{"class":392,"line":598},[390,1061,1062],{"class":601},"    throw",[390,1064,1065],{"class":408}," TimeoutException",[390,1067,657],{"class":400},[390,1069,1070],{"class":506},"'User fetch timed out after ",[390,1072,1073],{"class":400},"$",[390,1075,1076],{"class":666},"timeout",[390,1078,678],{"class":506},[390,1080,562],{"class":400},[390,1082,415],{"class":404},[390,1084,1085],{"class":392,"line":608},[390,1086,1087],{"class":400},"  }\n",[390,1089,1090],{"class":392,"line":627},[390,1091,688],{"class":400},[372,1093],{},[375,1095,1097],{"id":1096},"navigation-cancellation-in-flutter","Navigation Cancellation in Flutter",[348,1099,1100,1101,1104],{},"In a ",[351,1102,1103],{},"StatefulWidget",", tie the token to the widget lifecycle:",[380,1106,1109],{"className":382,"code":1107,"filename":1108,"language":385,"meta":386,"style":386},"class _UserScreenState extends State\u003CUserScreen> {\n  CancelToken? _fetchToken;\n\n  Future\u003Cvoid> _loadUser() async {\n    _fetchToken = CancelToken();\n    try {\n      await context.qora.fetchQuery\u003CUser>(\n        key: ['users', widget.userId],\n        fetcher: () => api.getUser(widget.userId),\n        cancelToken: _fetchToken,\n      );\n    } on QoraCancelException {\n      // Widget disposed: ignore\n    }\n  }\n\n  @override\n  void dispose() {\n    _fetchToken?.cancel();\n    super.dispose();\n  }\n}\n","user_screen.dart",[351,1110,1111,1133,1146,1150,1172,1185,1192,1215,1238,1265,1276,1283,1294,1299,1304,1308,1312,1317,1328,1343,1358,1363],{"__ignoreMap":386},[390,1112,1113,1116,1119,1122,1125,1127,1130],{"class":392,"line":393},[390,1114,1115],{"class":404},"class",[390,1117,1118],{"class":408}," _UserScreenState",[390,1120,1121],{"class":404}," extends",[390,1123,1124],{"class":408}," State",[390,1126,485],{"class":400},[390,1128,1129],{"class":408},"UserScreen",[390,1131,1132],{"class":400},"> {\n",[390,1134,1135,1138,1141,1144],{"class":392,"line":452},[390,1136,1137],{"class":408},"  CancelToken",[390,1139,1140],{"class":404},"?",[390,1142,1143],{"class":400}," _fetchToken",[390,1145,415],{"class":404},[390,1147,1148],{"class":392,"line":459},[390,1149,456],{"emptyLinePlaceholder":455},[390,1151,1152,1155,1157,1160,1162,1165,1168,1170],{"class":392,"line":466},[390,1153,1154],{"class":408},"  Future",[390,1156,485],{"class":400},[390,1158,1159],{"class":396},"void",[390,1161,899],{"class":400},[390,1163,1164],{"class":482},"_loadUser",[390,1166,1167],{"class":400},"() ",[390,1169,921],{"class":601},[390,1171,605],{"class":400},[390,1173,1174,1177,1179,1181,1183],{"class":392,"line":494},[390,1175,1176],{"class":400},"    _fetchToken ",[390,1178,405],{"class":404},[390,1180,409],{"class":408},[390,1182,412],{"class":400},[390,1184,415],{"class":404},[390,1186,1187,1190],{"class":392,"line":519},[390,1188,1189],{"class":601},"    try",[390,1191,605],{"class":400},[390,1193,1194,1197,1200,1202,1205,1207,1209,1211,1213],{"class":392,"line":546},[390,1195,1196],{"class":601},"      await",[390,1198,1199],{"class":400}," context",[390,1201,479],{"class":404},[390,1203,1204],{"class":400},"qora",[390,1206,479],{"class":404},[390,1208,357],{"class":482},[390,1210,485],{"class":400},[390,1212,488],{"class":408},[390,1214,491],{"class":400},[390,1216,1217,1220,1222,1224,1226,1228,1231,1233,1236],{"class":392,"line":559},[390,1218,1219],{"class":400},"        key",[390,1221,500],{"class":404},[390,1223,503],{"class":400},[390,1225,507],{"class":506},[390,1227,510],{"class":404},[390,1229,1230],{"class":400}," widget",[390,1232,479],{"class":404},[390,1234,1235],{"class":400},"userId]",[390,1237,516],{"class":404},[390,1239,1240,1243,1245,1247,1249,1251,1253,1255,1258,1260,1263],{"class":392,"line":567},[390,1241,1242],{"class":400},"        fetcher",[390,1244,500],{"class":404},[390,1246,527],{"class":400},[390,1248,530],{"class":404},[390,1250,533],{"class":400},[390,1252,479],{"class":404},[390,1254,538],{"class":482},[390,1256,1257],{"class":400},"(widget",[390,1259,479],{"class":404},[390,1261,1262],{"class":400},"userId)",[390,1264,516],{"class":404},[390,1266,1267,1270,1272,1274],{"class":392,"line":572},[390,1268,1269],{"class":400},"        cancelToken",[390,1271,500],{"class":404},[390,1273,1143],{"class":400},[390,1275,516],{"class":404},[390,1277,1278,1281],{"class":392,"line":578},[390,1279,1280],{"class":400},"      )",[390,1282,415],{"class":404},[390,1284,1285,1288,1290,1292],{"class":392,"line":593},[390,1286,1287],{"class":400},"    } ",[390,1289,633],{"class":601},[390,1291,636],{"class":408},[390,1293,605],{"class":400},[390,1295,1296],{"class":392,"line":598},[390,1297,1298],{"class":462},"      // Widget disposed: ignore\n",[390,1300,1301],{"class":392,"line":608},[390,1302,1303],{"class":400},"    }\n",[390,1305,1306],{"class":392,"line":627},[390,1307,1087],{"class":400},[390,1309,1310],{"class":392,"line":645},[390,1311,456],{"emptyLinePlaceholder":455},[390,1313,1314],{"class":392,"line":651},[390,1315,1316],{"class":396},"  @override\n",[390,1318,1319,1322,1325],{"class":392,"line":685},[390,1320,1321],{"class":396},"  void",[390,1323,1324],{"class":482}," dispose",[390,1326,1327],{"class":400},"() {\n",[390,1329,1331,1334,1337,1339,1341],{"class":392,"line":1330},19,[390,1332,1333],{"class":400},"    _fetchToken",[390,1335,1336],{"class":404},"?.",[390,1338,586],{"class":482},[390,1340,412],{"class":400},[390,1342,415],{"class":404},[390,1344,1346,1349,1351,1354,1356],{"class":392,"line":1345},20,[390,1347,1348],{"class":400},"    super",[390,1350,479],{"class":404},[390,1352,1353],{"class":482},"dispose",[390,1355,412],{"class":400},[390,1357,415],{"class":404},[390,1359,1361],{"class":392,"line":1360},21,[390,1362,1087],{"class":400},[390,1364,1366],{"class":392,"line":1365},22,[390,1367,688],{"class":400},[372,1369],{},[375,1371,1373,1375],{"id":1372},"canceltoken-api",[351,1374,353],{}," API",[1377,1378,1380],"h3",{"id":1379},"constructor","Constructor",[380,1382,1384],{"className":382,"code":1383,"language":385,"meta":386,"style":386},"CancelToken()\n",[351,1385,1386],{"__ignoreMap":386},[390,1387,1388,1390],{"class":392,"line":393},[390,1389,353],{"class":408},[390,1391,1392],{"class":400},"()\n",[1377,1394,1396],{"id":1395},"properties","Properties",[1398,1399,1400,1416],"table",{},[1401,1402,1403],"thead",{},[1404,1405,1406,1410,1413],"tr",{},[1407,1408,1409],"th",{},"Property",[1407,1411,1412],{},"Type",[1407,1414,1415],{},"Description",[1417,1418,1419],"tbody",{},[1404,1420,1421,1427,1432],{},[1422,1423,1424],"td",{},[351,1425,1426],{},"isCancelled",[1422,1428,1429],{},[351,1430,1431],{},"bool",[1422,1433,1434,1437,1438,1440],{},[351,1435,1436],{},"true"," after ",[351,1439,369],{}," is called.",[1377,1442,1444],{"id":1443},"methods","Methods",[1398,1446,1447,1459],{},[1401,1448,1449],{},[1404,1450,1451,1454,1457],{},[1407,1452,1453],{},"Method",[1407,1455,1456],{},"Signature",[1407,1458,1415],{},[1417,1460,1461],{},[1404,1462,1463,1467,1471],{},[1422,1464,1465],{},[351,1466,369],{},[1422,1468,1469],{},[351,1470,1159],{},[1422,1472,1473],{},"Mark the token as cancelled. Idempotent and safe to call multiple times.",[372,1475],{},[375,1477,1479],{"id":1478},"qoracancelexception",[351,1480,697],{},[348,1482,1483,1484,1486,1487,1489,1490,479],{},"Thrown by ",[351,1485,357],{}," and ",[351,1488,365],{}," when a fetch is cancelled via ",[351,1491,353],{},[380,1493,1495],{"className":382,"code":1494,"language":385,"meta":386,"style":386},"class QoraCancelException implements Exception {\n  final String key; // JSON-encoded normalised query key\n}\n",[351,1496,1497,1511,1527],{"__ignoreMap":386},[390,1498,1499,1501,1503,1506,1509],{"class":392,"line":393},[390,1500,1115],{"class":404},[390,1502,636],{"class":408},[390,1504,1505],{"class":404}," implements",[390,1507,1508],{"class":408}," Exception",[390,1510,605],{"class":400},[390,1512,1513,1515,1518,1521,1524],{"class":392,"line":452},[390,1514,611],{"class":396},[390,1516,1517],{"class":408}," String",[390,1519,1520],{"class":400}," key",[390,1522,1523],{"class":404},";",[390,1525,1526],{"class":462}," // JSON-encoded normalised query key\n",[390,1528,1529],{"class":392,"line":459},[390,1530,688],{"class":400},[1398,1532,1533,1543],{},[1401,1534,1535],{},[1404,1536,1537,1539,1541],{},[1407,1538,1409],{},[1407,1540,1412],{},[1407,1542,1415],{},[1417,1544,1545],{},[1404,1546,1547,1551,1556],{},[1422,1548,1549],{},[351,1550,672],{},[1422,1552,1553],{},[351,1554,1555],{},"String",[1422,1557,1558,1559],{},"The string-encoded query key, e.g. ",[351,1560,1561],{},"'[\"users\",1]'",[372,1563],{},[375,1565,1567],{"id":1566},"tracker-hook","Tracker Hook",[348,1569,1570,1573,1574,1576],{},[351,1571,1572],{},"QoraTracker.onQueryCancelled(String key)"," is called every time a fetch is cancelled via ",[351,1575,353],{},". Implement it on your custom tracker to log or measure cancellation rates:",[380,1578,1581],{"className":382,"code":1579,"filename":1580,"language":385,"meta":386,"style":386},"class AnalyticsTracker extends NoOpTracker {\n  @override\n  void onQueryCancelled(String key) {\n    analytics.track('query_cancelled', {'key': key});\n  }\n}\n","analytics_tracker.dart",[351,1582,1583,1597,1601,1615,1645,1649],{"__ignoreMap":386},[390,1584,1585,1587,1590,1592,1595],{"class":392,"line":393},[390,1586,1115],{"class":404},[390,1588,1589],{"class":408}," AnalyticsTracker",[390,1591,1121],{"class":404},[390,1593,1594],{"class":408}," NoOpTracker",[390,1596,605],{"class":400},[390,1598,1599],{"class":392,"line":452},[390,1600,1316],{"class":396},[390,1602,1603,1605,1608,1610,1612],{"class":392,"line":459},[390,1604,1321],{"class":396},[390,1606,1607],{"class":482}," onQueryCancelled",[390,1609,657],{"class":400},[390,1611,1555],{"class":408},[390,1613,1614],{"class":400}," key) {\n",[390,1616,1617,1620,1622,1625,1627,1630,1632,1635,1638,1640,1643],{"class":392,"line":466},[390,1618,1619],{"class":400},"    analytics",[390,1621,479],{"class":404},[390,1623,1624],{"class":482},"track",[390,1626,657],{"class":400},[390,1628,1629],{"class":506},"'query_cancelled'",[390,1631,510],{"class":404},[390,1633,1634],{"class":400}," {",[390,1636,1637],{"class":506},"'key'",[390,1639,500],{"class":404},[390,1641,1642],{"class":400}," key})",[390,1644,415],{"class":404},[390,1646,1647],{"class":392,"line":494},[390,1648,1087],{"class":400},[390,1650,1651],{"class":392,"line":519},[390,1652,688],{"class":400},[372,1654],{},[375,1656,1658],{"id":1657},"related","Related",[1660,1661,1662,1678],"ul",{},[1663,1664,1665,1670,1671,358,1673,358,1675,1677],"li",{},[1666,1667,1669],"a",{"href":1668},"../api-reference/qora-client","QoraClient API",": ",[351,1672,357],{},[351,1674,361],{},[351,1676,365],{}," signatures",[1663,1679,1680,1683],{},[1666,1681,1682],{"href":1668},"QoraTracker",": Observability hooks",[1685,1686,1687],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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 .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);}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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":386,"searchDepth":452,"depth":452,"links":1689},[1690,1691,1693,1695,1696,1697,1703,1704,1705],{"id":377,"depth":452,"text":378},{"id":426,"depth":452,"text":1692},"Cancelling a fetchQuery",{"id":703,"depth":452,"text":1694},"Cancelling a watchQuery stream",{"id":871,"depth":452,"text":872},{"id":1096,"depth":452,"text":1097},{"id":1372,"depth":452,"text":1698,"children":1699},"CancelToken API",[1700,1701,1702],{"id":1379,"depth":459,"text":1380},{"id":1395,"depth":459,"text":1396},{"id":1443,"depth":459,"text":1444},{"id":1478,"depth":452,"text":697},{"id":1566,"depth":452,"text":1567},{"id":1657,"depth":452,"text":1658},"Use CancelToken to abort in-flight fetches cooperatively: on navigation, timeout, or user action.","md",null,{},{"icon":175},{"title":172,"description":1706},"XcDg85_oNzlB-PstDLtlGeFuvlZ4OyotyRoBYwisog4",[1714,1716],{"title":167,"path":168,"stem":169,"description":1715,"icon":170,"children":-1},"Use QoraOptions.dependsOn to chain queries so one fires only after another resolves.",{"title":177,"path":178,"stem":179,"description":1717,"icon":180,"children":-1},"Eliminate the loading flash on server-rendered Flutter Web pages by injecting the server cache into QoraClient via SsrHydrator.",1794040399450]