[{"data":1,"prerenderedAt":1238},["ShallowReactive",2],{"navigation_docs_en":3,"-en-core-concepts-mutations":342,"-en-core-concepts-mutations-surround":1233},[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":82,"body":344,"description":1226,"extension":1227,"links":1228,"meta":1229,"navigation":1230,"path":83,"seo":1231,"stem":84,"__hash__":1232},"docs_en/en/02.core-concepts/7.mutations.md",{"type":345,"value":346,"toc":1216},"minimark",[347,356,359,364,367,378,381,387,412,416,486,489,493,500,676,687,729,732,735,828,835,838,841,1140,1153,1157,1160,1178,1182,1212],[348,349,350,351,355],"p",{},"A query reads server data and keeps it in the cache. A ",[352,353,354],"strong",{},"mutation"," changes server data: create, update, delete. Mutations are not cached and not deduplicated; they run when you call them, once per call.",[348,357,358],{},"The hard part of a write is not sending it. It is what happens to the cached data afterwards: the list that should now contain the new item, the detail screen that shows the old title. This page is about that part.",[360,361,363],"h2",{"id":362},"the-lifecycle","The lifecycle",[348,365,366],{},"A mutation moves through four states:",[368,369,375],"pre",{"className":370,"code":372,"language":373,"meta":374},[371],"language-text","MutationIdle ──mutate()──▶ MutationPending ──▶ MutationSuccess\n                                         └──▶ MutationFailure\n","text","",[376,377,372],"code",{"__ignoreMap":374},[348,379,380],{},"Its callbacks run in a fixed order. Knowing it tells you where each piece of logic belongs:",[368,382,385],{"className":383,"code":384,"language":373,"meta":374},[371],"mutate(variables)\n  1. onMutate(variables)            → returns a context (usually a snapshot)\n  2. state: MutationPending\n  3. mutator(variables)             → retried retryCount times (default 0)\n  success:\n  4. state: MutationSuccess\n  5. onSuccess(data, variables, context)\n  6. invalidates, then invalidatesTags\n  7. onSettled(data, null, variables, context)\n  failure:\n  4. state: MutationFailure\n  5. onError(error, variables, context)\n  6. onSettled(null, error, variables, context)\n",[376,386,384],{"__ignoreMap":374},[348,388,389,390,393,394,397,398,401,402,404,405,408,409,411],{},"The ",[376,391,392],{},"context"," returned by ",[376,395,396],{},"onMutate"," is passed to every later callback. That is how a rollback in ",[376,399,400],{},"onError"," knows what to restore. If ",[376,403,396],{}," itself throws, the mutation goes straight to ",[376,406,407],{},"MutationFailure",": the mutator is not called, and neither is ",[376,410,400],{},".",[360,413,415],{"id":414},"three-ways-to-update-the-cache-after-a-write","Three ways to update the cache after a write",[417,418,419,435],"table",{},[420,421,422],"thead",{},[423,424,425,429,432],"tr",{},[426,427,428],"th",{},"Strategy",[426,430,431],{},"What you do",[426,433,434],{},"Use it when",[436,437,438,452,468],"tbody",{},[423,439,440,446,449],{},[441,442,443],"td",{},[352,444,445],{},"Invalidate",[441,447,448],{},"Mark the affected queries stale; they refetch",[441,450,451],{},"The default. The server is the source of truth and one extra request is acceptable",[423,453,454,459,465],{},[441,455,456],{},[352,457,458],{},"Write the response",[441,460,461,462],{},"Put the server's response in the cache with ",[376,463,464],{},"setQueryData",[441,466,467],{},"The server returns the updated entity, and you want to skip the refetch",[423,469,470,475,483],{},[441,471,472],{},[352,473,474],{},"Optimistic update",[441,476,477,478,480,481],{},"Change the cache in ",[376,479,396],{},", roll back in ",[376,482,400],{},[441,484,485],{},"The result is predictable and the UI must react instantly, or work offline",[348,487,488],{},"They combine. The most robust pattern is an optimistic update followed by an invalidation: the UI changes immediately, and the refetch replaces your guess with what the server actually stored.",[490,491,445],"h3",{"id":492},"invalidate",[348,494,495,496,499],{},"Declare the keys a mutation affects; Qora invalidates them after ",[376,497,498],{},"onSuccess",":",[368,501,505],{"className":502,"code":503,"language":504,"meta":374,"style":374},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","QoraMutationBuilder\u003CTodo, String, void>(\n  mutator: (title) => api.createTodo(title),\n  options: const MutationOptions(invalidates: [['todos']]),\n  builder: (context, state, mutate) => AddTodoField(\n    enabled: !state.isPending,\n    onSubmit: mutate,\n  ),\n)\n","dart",[376,506,507,537,567,598,628,649,662,670],{"__ignoreMap":374},[508,509,512,515,519,522,525,528,530,534],"span",{"class":510,"line":511},"line",1,[508,513,113],{"class":514},"sBMFI",[508,516,518],{"class":517},"sTEyZ","\u003C",[508,520,521],{"class":514},"Todo",[508,523,524],{"class":517},", ",[508,526,527],{"class":514},"String",[508,529,524],{"class":517},[508,531,533],{"class":532},"spNyl","void",[508,535,536],{"class":517},">(\n",[508,538,540,543,546,549,552,555,557,561,564],{"class":510,"line":539},2,[508,541,542],{"class":517},"  mutator",[508,544,499],{"class":545},"sMK4o",[508,547,548],{"class":517}," (title) ",[508,550,551],{"class":545},"=>",[508,553,554],{"class":517}," api",[508,556,411],{"class":545},[508,558,560],{"class":559},"s2Zo4","createTodo",[508,562,563],{"class":517},"(title)",[508,565,566],{"class":545},",\n",[508,568,570,573,575,578,581,584,586,589,593,596],{"class":510,"line":569},3,[508,571,572],{"class":517},"  options",[508,574,499],{"class":545},[508,576,577],{"class":532}," const",[508,579,580],{"class":514}," MutationOptions",[508,582,583],{"class":517},"(invalidates",[508,585,499],{"class":545},[508,587,588],{"class":517}," [[",[508,590,592],{"class":591},"sfazB","'todos'",[508,594,595],{"class":517},"]])",[508,597,566],{"class":545},[508,599,601,604,606,609,612,615,617,620,622,625],{"class":510,"line":600},4,[508,602,603],{"class":517},"  builder",[508,605,499],{"class":545},[508,607,608],{"class":517}," (context",[508,610,611],{"class":545},",",[508,613,614],{"class":517}," state",[508,616,611],{"class":545},[508,618,619],{"class":517}," mutate) ",[508,621,551],{"class":545},[508,623,624],{"class":514}," AddTodoField",[508,626,627],{"class":517},"(\n",[508,629,631,634,636,639,642,644,647],{"class":510,"line":630},5,[508,632,633],{"class":517},"    enabled",[508,635,499],{"class":545},[508,637,638],{"class":545}," !",[508,640,641],{"class":517},"state",[508,643,411],{"class":545},[508,645,646],{"class":517},"isPending",[508,648,566],{"class":545},[508,650,652,655,657,660],{"class":510,"line":651},6,[508,653,654],{"class":517},"    onSubmit",[508,656,499],{"class":545},[508,658,659],{"class":517}," mutate",[508,661,566],{"class":545},[508,663,665,668],{"class":510,"line":664},7,[508,666,667],{"class":517},"  )",[508,669,566],{"class":545},[508,671,673],{"class":510,"line":672},8,[508,674,675],{"class":517},")\n",[348,677,678,679,682,683,686],{},"Invalidating a key marks its data stale. A query that is on screen refetches immediately; meanwhile its state is ",[376,680,681],{},"Loading"," with the old data as ",[376,684,685],{},"previousData",", so the screen can keep showing it. A query that is not on screen refetches the next time a widget uses it.",[688,689,690,693,694,697,698,701,702,705,706,709,710,713,714,716,717,720,721,724,725,411],"warning",{},[376,691,692],{},"invalidates"," matches ",[352,695,696],{},"exact keys",". ",[376,699,700],{},"[['todos']]"," invalidates ",[376,703,704],{},"['todos']",", not ",[376,707,708],{},"['todos', 42]",". To invalidate a whole family, call ",[376,711,712],{},"client.invalidatePrefix(['todos'])"," in ",[376,715,498],{},", or use tags (",[376,718,719],{},"providesTags"," on the queries, ",[376,722,723],{},"invalidatesTags"," on the mutation). See ",[726,727,57],"a",{"href":728},"./query-keys",[490,730,458],{"id":731},"write-the-response",[348,733,734],{},"When the server returns the updated entity, put it in the cache instead of refetching it:",[368,736,738],{"className":502,"code":737,"language":504,"meta":374,"style":374},"options: MutationOptions(\n  onSuccess: (updated, _, __) async {\n    client.setQueryData\u003CTodo>(['todos', updated.id], updated);\n  },\n),\n",[376,739,740,751,778,814,821],{"__ignoreMap":374},[508,741,742,745,747,749],{"class":510,"line":511},[508,743,744],{"class":517},"options",[508,746,499],{"class":545},[508,748,580],{"class":514},[508,750,627],{"class":517},[508,752,753,756,758,761,763,766,768,771,775],{"class":510,"line":539},[508,754,755],{"class":517},"  onSuccess",[508,757,499],{"class":545},[508,759,760],{"class":517}," (updated",[508,762,611],{"class":545},[508,764,765],{"class":517}," _",[508,767,611],{"class":545},[508,769,770],{"class":517}," __) ",[508,772,774],{"class":773},"s7zQu","async",[508,776,777],{"class":517}," {\n",[508,779,780,783,785,787,789,791,794,796,798,801,803,806,808,811],{"class":510,"line":569},[508,781,782],{"class":517},"    client",[508,784,411],{"class":545},[508,786,464],{"class":559},[508,788,518],{"class":517},[508,790,521],{"class":514},[508,792,793],{"class":517},">([",[508,795,592],{"class":591},[508,797,611],{"class":545},[508,799,800],{"class":517}," updated",[508,802,411],{"class":545},[508,804,805],{"class":517},"id]",[508,807,611],{"class":545},[508,809,810],{"class":517}," updated)",[508,812,813],{"class":545},";\n",[508,815,816,819],{"class":510,"line":600},[508,817,818],{"class":517},"  }",[508,820,566],{"class":545},[508,822,823,826],{"class":510,"line":630},[508,824,825],{"class":517},")",[508,827,566],{"class":545},[348,829,830,831,834],{},"Every widget showing ",[376,832,833],{},"['todos', updated.id]"," rebuilds with the new value, and no request is made. Lists that contain the item are a separate key: invalidate them, or update them the same way.",[490,836,474],{"id":837},"optimistic-update",[348,839,840],{},"Change the cache before the server answers, keep a snapshot, and restore it on failure:",[368,842,844],{"className":502,"code":843,"language":504,"meta":374,"style":374},"options: MutationOptions\u003CTodo, Todo, List\u003CTodo>?>(\n  onMutate: (todo) async {\n    final previous = client.getQueryData\u003CList\u003CTodo>>(['todos']);\n    client.setQueryData\u003CList\u003CTodo>>(\n      ['todos'],\n      [for (final t in previous ?? \u003CTodo>[]) t.id == todo.id ? todo : t],\n    );\n    return previous; // becomes `context` in the other callbacks\n  },\n  onError: (_, __, previous) async {\n    client.restoreQueryData\u003CList\u003CTodo>>(['todos'], previous);\n  },\n  invalidates: const [['todos']], // reconcile with the server either way\n),\n",[376,845,846,874,888,925,944,956,1019,1026,1041,1048,1073,1104,1111,1133],{"__ignoreMap":374},[508,847,848,850,852,854,856,858,860,862,864,867,869,871],{"class":510,"line":511},[508,849,744],{"class":517},[508,851,499],{"class":545},[508,853,580],{"class":514},[508,855,518],{"class":517},[508,857,521],{"class":514},[508,859,524],{"class":517},[508,861,521],{"class":514},[508,863,524],{"class":517},[508,865,866],{"class":514},"List",[508,868,518],{"class":517},[508,870,521],{"class":514},[508,872,873],{"class":517},">?>(\n",[508,875,876,879,881,884,886],{"class":510,"line":539},[508,877,878],{"class":517},"  onMutate",[508,880,499],{"class":545},[508,882,883],{"class":517}," (todo) ",[508,885,774],{"class":773},[508,887,777],{"class":517},[508,889,890,893,896,899,902,904,907,909,911,913,915,918,920,923],{"class":510,"line":569},[508,891,892],{"class":532},"    final",[508,894,895],{"class":517}," previous ",[508,897,898],{"class":545},"=",[508,900,901],{"class":517}," client",[508,903,411],{"class":545},[508,905,906],{"class":559},"getQueryData",[508,908,518],{"class":517},[508,910,866],{"class":514},[508,912,518],{"class":517},[508,914,521],{"class":514},[508,916,917],{"class":517},">>([",[508,919,592],{"class":591},[508,921,922],{"class":517},"])",[508,924,813],{"class":545},[508,926,927,929,931,933,935,937,939,941],{"class":510,"line":600},[508,928,782],{"class":517},[508,930,411],{"class":545},[508,932,464],{"class":559},[508,934,518],{"class":517},[508,936,866],{"class":514},[508,938,518],{"class":517},[508,940,521],{"class":514},[508,942,943],{"class":517},">>(\n",[508,945,946,949,951,954],{"class":510,"line":630},[508,947,948],{"class":517},"      [",[508,950,592],{"class":591},[508,952,953],{"class":517},"]",[508,955,566],{"class":545},[508,957,958,960,963,966,969,972,975,977,980,983,985,988,991,993,996,999,1002,1004,1006,1009,1012,1014,1017],{"class":510,"line":651},[508,959,948],{"class":517},[508,961,962],{"class":773},"for",[508,964,965],{"class":517}," (",[508,967,968],{"class":532},"final",[508,970,971],{"class":517}," t ",[508,973,974],{"class":773},"in",[508,976,895],{"class":517},[508,978,979],{"class":545},"??",[508,981,982],{"class":545}," \u003C",[508,984,521],{"class":514},[508,986,987],{"class":545},">",[508,989,990],{"class":517},"[]) t",[508,992,411],{"class":545},[508,994,995],{"class":517},"id ",[508,997,998],{"class":545},"==",[508,1000,1001],{"class":517}," todo",[508,1003,411],{"class":545},[508,1005,995],{"class":517},[508,1007,1008],{"class":545},"?",[508,1010,1011],{"class":517}," todo ",[508,1013,499],{"class":545},[508,1015,1016],{"class":517}," t]",[508,1018,566],{"class":545},[508,1020,1021,1024],{"class":510,"line":664},[508,1022,1023],{"class":517},"    )",[508,1025,813],{"class":545},[508,1027,1028,1031,1034,1037],{"class":510,"line":672},[508,1029,1030],{"class":773},"    return",[508,1032,1033],{"class":517}," previous",[508,1035,1036],{"class":545},";",[508,1038,1040],{"class":1039},"sHwdD"," // becomes `context` in the other callbacks\n",[508,1042,1044,1046],{"class":510,"line":1043},9,[508,1045,818],{"class":517},[508,1047,566],{"class":545},[508,1049,1051,1054,1056,1059,1061,1064,1066,1069,1071],{"class":510,"line":1050},10,[508,1052,1053],{"class":517},"  onError",[508,1055,499],{"class":545},[508,1057,1058],{"class":517}," (_",[508,1060,611],{"class":545},[508,1062,1063],{"class":517}," __",[508,1065,611],{"class":545},[508,1067,1068],{"class":517}," previous) ",[508,1070,774],{"class":773},[508,1072,777],{"class":517},[508,1074,1076,1078,1080,1083,1085,1087,1089,1091,1093,1095,1097,1099,1102],{"class":510,"line":1075},11,[508,1077,782],{"class":517},[508,1079,411],{"class":545},[508,1081,1082],{"class":559},"restoreQueryData",[508,1084,518],{"class":517},[508,1086,866],{"class":514},[508,1088,518],{"class":517},[508,1090,521],{"class":514},[508,1092,917],{"class":517},[508,1094,592],{"class":591},[508,1096,953],{"class":517},[508,1098,611],{"class":545},[508,1100,1101],{"class":517}," previous)",[508,1103,813],{"class":545},[508,1105,1107,1109],{"class":510,"line":1106},12,[508,1108,818],{"class":517},[508,1110,566],{"class":545},[508,1112,1114,1117,1119,1121,1123,1125,1128,1130],{"class":510,"line":1113},13,[508,1115,1116],{"class":517},"  invalidates",[508,1118,499],{"class":545},[508,1120,577],{"class":532},[508,1122,588],{"class":517},[508,1124,592],{"class":591},[508,1126,1127],{"class":517},"]]",[508,1129,611],{"class":545},[508,1131,1132],{"class":1039}," // reconcile with the server either way\n",[508,1134,1136,1138],{"class":510,"line":1135},14,[508,1137,825],{"class":517},[508,1139,566],{"class":545},[348,1141,1142,1144,1145,1148,1149,1152],{},[376,1143,1082],{}," puts the snapshot back, or removes the entry if the snapshot is ",[376,1146,1147],{},"null",". The ",[726,1150,148],{"href":1151},"../recipes/optimistic-updates"," recipe covers lists, multiple keys and concurrent edits.",[360,1154,1156],{"id":1155},"mutations-and-the-network","Mutations and the network",[348,1158,1159],{},"By default a mutation sends its request immediately. While the device is offline that request fails like any network error, and the failure path above runs.",[348,1161,1162,1163,1166,1167,1170,1171,1173,1174,1177],{},"With ",[376,1164,1165],{},"offlineQueue: true",", a mutation called while offline is ",[352,1168,1169],{},"queued"," instead: ",[376,1172,396],{}," runs right away, so optimistic updates work offline, and the request is sent when the device reconnects. ",[726,1175,87],{"href":1176},"./offline"," explains the queue, its order and its limits.",[360,1179,1181],{"id":1180},"next-steps","Next Steps",[1183,1184,1185,1191,1201,1206],"ul",{},[1186,1187,1188,1190],"li",{},[726,1189,87],{"href":1176},": paused queries, the mutation queue, reconnect",[1186,1192,1193,1197,1198,1200],{},[726,1194,1196],{"href":1195},"../recipes/mutations","Mutations recipe",": ",[376,1199,113],{},", retries, tags, standalone controllers",[1186,1202,1203,1205],{},[726,1204,148],{"href":1151},": patterns for lists and multiple keys",[1186,1207,1208,1211],{},[726,1209,113],{"href":1210},"../flutter-integration/qora-mutation-builder",": the widget API",[1213,1214,1215],"style",{},"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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .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 .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 .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}",{"title":374,"searchDepth":539,"depth":539,"links":1217},[1218,1219,1224,1225],{"id":362,"depth":539,"text":363},{"id":414,"depth":539,"text":415,"children":1220},[1221,1222,1223],{"id":492,"depth":569,"text":445},{"id":731,"depth":569,"text":458},{"id":837,"depth":569,"text":474},{"id":1155,"depth":539,"text":1156},{"id":1180,"depth":539,"text":1181},"How writes run, in which order their callbacks fire, and the three ways to bring the cache back in line with the server afterwards.","md",null,{},{"icon":85},{"title":82,"description":1226},"CldmmHL6qLLFcfU8bwMaYYLGL4B1e0kcZfrYpjK7mog",[1234,1236],{"title":77,"path":78,"stem":79,"description":1235,"icon":80,"children":-1},"Qora merges concurrent requests for the same key into a single network call, regardless of the number of callers.",{"title":87,"path":88,"stem":89,"description":1237,"icon":90,"children":-1},"What Qora does with reads and writes while the device is offline, what happens on reconnect, and what survives an app restart.",1794040398991]