[{"data":1,"prerenderedAt":2776},["ShallowReactive",2],{"navigation_docs_fr":3,"-fr-recipes-optimistic-updates":342,"-fr-recipes-optimistic-updates-surround":2771},[4,45,91,137,195,236,257,291,327],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Prise en main","i-lucide-rocket","/fr/getting-started","fr/01.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Qu'est-ce que Qora ?","/fr/getting-started/what-is-qora","fr/01.getting-started/2.what-is-qora","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Installation","/fr/getting-started/installation","fr/01.getting-started/3.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":6},"Démarrage rapide","/fr/getting-started/quick-start","fr/01.getting-started/4.quick-start",{"title":25,"path":26,"stem":27,"icon":28},"Comparaison","/fr/getting-started/comparison","fr/01.getting-started/5.comparison","i-lucide-scale",{"title":30,"path":31,"stem":32,"icon":33},"Venant de TanStack Query","/fr/getting-started/coming-from-tanstack-query","fr/01.getting-started/6.coming-from-tanstack-query","i-lucide-arrow-left-right",{"title":35,"path":36,"stem":37,"icon":38},"Migrer depuis d'Autres Librairies","/fr/getting-started/migrating-from-other-libraries","fr/01.getting-started/7.migrating-from-other-libraries","i-lucide-arrow-right-left",{"title":40,"path":41,"stem":42,"icon":43},"Assistants IA","/fr/getting-started/ai-assistants","fr/01.getting-started/8.ai-assistants","i-lucide-sparkles",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Concepts clés","i-lucide-book-open","/fr/core-concepts","fr/02.core-concepts",[51,56,61,66,71,76,81,86],{"title":52,"path":53,"stem":54,"icon":55},"Requêtes","/fr/core-concepts/queries","fr/02.core-concepts/1.queries","i-lucide-database",{"title":57,"path":58,"stem":59,"icon":60},"Clés de requête","/fr/core-concepts/query-keys","fr/02.core-concepts/2.query-keys","i-lucide-key-round",{"title":62,"path":63,"stem":64,"icon":65},"États des requêtes","/fr/core-concepts/query-states","fr/02.core-concepts/3.query-states","i-lucide-activity",{"title":67,"path":68,"stem":69,"icon":70},"Cache","/fr/core-concepts/caching","fr/02.core-concepts/4.caching","i-lucide-layers-3",{"title":72,"path":73,"stem":74,"icon":75},"Stale-While-Revalidate","/fr/core-concepts/stale-while-revalidate","fr/02.core-concepts/5.stale-while-revalidate","i-lucide-timer-reset",{"title":77,"path":78,"stem":79,"icon":80},"Déduplication","/fr/core-concepts/deduplication","fr/02.core-concepts/6.deduplication","i-lucide-copy-minus",{"title":82,"path":83,"stem":84,"icon":85},"Mutations et invalidation","/fr/core-concepts/mutations","fr/02.core-concepts/7.mutations","i-lucide-pencil-line",{"title":87,"path":88,"stem":89,"icon":90},"Hors-ligne et réseau","/fr/core-concepts/offline","fr/02.core-concepts/8.offline","i-lucide-wifi-off",{"title":92,"icon":93,"path":94,"stem":95,"children":96,"page":44},"Usage avec Flutter","i-lucide-smartphone","/fr/flutter-integration","fr/03.flutter-integration",[97,102,107,112,117,122,127,132],{"title":98,"path":99,"stem":100,"icon":101},"Configuration","/fr/flutter-integration/setup","fr/03.flutter-integration/1.setup","i-lucide-wrench",{"title":103,"path":104,"stem":105,"icon":106},"QoraScope","/fr/flutter-integration/qora-scope","fr/03.flutter-integration/2.qora-scope","i-lucide-share-2",{"title":108,"path":109,"stem":110,"icon":111},"QoraBuilder","/fr/flutter-integration/qora-builder","fr/03.flutter-integration/3.qora-builder","i-lucide-blocks",{"title":113,"path":114,"stem":115,"icon":116},"QoraMutationBuilder","/fr/flutter-integration/qora-mutation-builder","fr/03.flutter-integration/4.qora-mutation-builder","i-lucide-pencil",{"title":118,"path":119,"stem":120,"icon":121},"InfiniteQueryBuilder","/fr/flutter-integration/infinite-query-builder","fr/03.flutter-integration/5.infinite-query-builder","i-lucide-infinity",{"title":123,"path":124,"stem":125,"icon":126},"Hooks (flutter_hooks)","/fr/flutter-integration/hooks","fr/03.flutter-integration/6.hooks","i-lucide-anchor",{"title":128,"path":129,"stem":130,"icon":131},"Widgets de statut réseau","/fr/flutter-integration/network-status","fr/03.flutter-integration/7.network-status","i-lucide-wifi",{"title":133,"path":134,"stem":135,"icon":136},"Bonnes pratiques","/fr/flutter-integration/best-practices","fr/03.flutter-integration/8.best-practices","i-lucide-badge-check",{"title":138,"icon":139,"path":140,"stem":141,"children":142,"page":44},"Guides Pratiques","i-lucide-chef-hat","/fr/recipes","fr/04.recipes",[143,147,152,157,162,166,171,176,181,186,191],{"title":144,"path":145,"stem":146,"icon":85},"Mutations","/fr/recipes/mutations","fr/04.recipes/02.mutations",{"title":148,"path":149,"stem":150,"icon":151},"Mises à jour optimistes","/fr/recipes/optimistic-updates","fr/04.recipes/03.optimistic-updates","i-lucide-zap",{"title":153,"path":154,"stem":155,"icon":156},"Persistance","/fr/recipes/persistence","fr/04.recipes/04.persistence","i-lucide-hard-drive",{"title":158,"path":159,"stem":160,"icon":161},"Réseau adaptatif","/fr/recipes/network-aware","fr/04.recipes/05.network-aware","i-lucide-signal",{"title":163,"path":164,"stem":165,"icon":121},"Requêtes infinies","/fr/recipes/infinite-queries","fr/04.recipes/06.infinite-queries",{"title":167,"path":168,"stem":169,"icon":170},"Requêtes dépendantes","/fr/recipes/dependent-queries","fr/04.recipes/07.dependent-queries","i-lucide-link-2",{"title":172,"path":173,"stem":174,"icon":175},"Annulation","/fr/recipes/cancel-token","fr/04.recipes/08.cancel-token","i-lucide-circle-slash",{"title":177,"path":178,"stem":179,"icon":180},"Hydratation SSR","/fr/recipes/ssr-hydration","fr/04.recipes/09.ssr-hydration","i-lucide-server",{"title":182,"path":183,"stem":184,"icon":185},"Gestion des erreurs","/fr/recipes/error-handling","fr/04.recipes/10.error-handling","i-lucide-shield-alert",{"title":187,"path":188,"stem":189,"icon":190},"Tests","/fr/recipes/testing","fr/04.recipes/11.testing","i-lucide-flask-conical",{"title":192,"path":193,"stem":194},"Prefetch au Niveau des Routes","/fr/recipes/prefetch","fr/04.recipes/12.prefetch",{"title":196,"icon":197,"path":198,"stem":199,"children":200,"page":44},"Référence de l'API","i-lucide-file-code","/fr/api-reference","fr/05.api-reference",[201,206,210,214,219,224,228,232],{"title":202,"path":203,"stem":204,"icon":205},"QoraClient","/fr/api-reference/qora-client","fr/05.api-reference/1.qora-client","i-lucide-cpu",{"title":207,"path":208,"stem":209,"icon":60},"QoraKey","/fr/api-reference/qora-key","fr/05.api-reference/2.qora-key",{"title":211,"path":212,"stem":213,"icon":65},"QoraState","/fr/api-reference/qora-state","fr/05.api-reference/3.qora-state",{"title":215,"path":216,"stem":217,"icon":218},"QoraOptions","/fr/api-reference/qora-options","fr/05.api-reference/4.qora-options","i-lucide-sliders-horizontal",{"title":220,"path":221,"stem":222,"icon":223},"QoraClientConfig","/fr/api-reference/qora-client-config","fr/05.api-reference/5.qora-client-config","i-lucide-settings-2",{"title":225,"path":226,"stem":227,"icon":85},"API Mutation","/fr/api-reference/qora-mutation","fr/05.api-reference/6.qora-mutation",{"title":229,"path":230,"stem":231,"icon":156},"PersistQoraClient","/fr/api-reference/persist-qora-client","fr/05.api-reference/7.persist-qora-client",{"title":233,"path":234,"stem":235,"icon":121},"Requête infinie","/fr/api-reference/infinite-query","fr/05.api-reference/8.infinite-query",{"title":237,"icon":238,"path":239,"stem":240,"children":241,"page":44},"Outils de debug","i-lucide-bug","/fr/devtools","fr/06.devtools",[242,247,252],{"title":243,"path":244,"stem":245,"icon":246},"Vue d'ensemble","/fr/devtools/overview","fr/06.devtools/1.overview","i-lucide-layout-dashboard",{"title":248,"path":249,"stem":250,"icon":251},"Overlay intégré","/fr/devtools/overlay","fr/06.devtools/2.overlay","i-lucide-layers",{"title":253,"path":254,"stem":255,"icon":256},"Sérialisation des données","/fr/devtools/data-display","fr/06.devtools/4.data-display","i-lucide-eye",{"title":258,"icon":259,"path":260,"stem":261,"children":262,"page":44},"Intégrations tierces","i-lucide-puzzle","/fr/third-party","fr/07.third-party",[263,268,272,277,282,286],{"title":264,"path":265,"stem":266,"icon":267},"Avec Provider","/fr/third-party/with-provider","fr/07.third-party/1.with-provider","i-lucide-plug",{"title":269,"path":270,"stem":271,"icon":111},"Avec BLoC","/fr/third-party/with-bloc","fr/07.third-party/2.with-bloc",{"title":273,"path":274,"stem":275,"icon":276},"Avec Riverpod","/fr/third-party/with-riverpod","fr/07.third-party/3.with-riverpod","i-lucide-droplets",{"title":278,"path":279,"stem":280,"icon":281},"Avec RxDart","/fr/third-party/with-rxdart","fr/07.third-party/4.with-rxdart","i-lucide-git-branch",{"title":283,"path":284,"stem":285},"Avec Dio","/fr/third-party/with-dio","fr/07.third-party/5.with-dio",{"title":287,"path":288,"stem":289,"icon":290},"Avec GraphQL","/fr/third-party/with-graphql","fr/07.third-party/6.with-graphql","i-lucide-binary",{"title":292,"icon":190,"path":293,"stem":294,"children":295,"page":44},"Exemples","/fr/examples","fr/08.examples",[296,301,305,310,314,318,322],{"title":297,"path":298,"stem":299,"icon":300},"Étude de cas : Liste et détail utilisateur","/fr/examples/basic-query","fr/08.examples/1.basic-query","i-lucide-play-circle",{"title":302,"path":303,"stem":304,"icon":151},"Étude de cas : Mutations optimistes et rollback","/fr/examples/mutations-optimistic","fr/08.examples/2.mutations-optimistic",{"title":306,"path":307,"stem":308,"icon":309},"Étude de cas : Feed à défilement infini","/fr/examples/infinite-scroll","fr/08.examples/3.infinite-scroll","i-lucide-scroll",{"title":311,"path":312,"stem":313,"icon":90},"Étude de cas : Application Todo offline-first","/fr/examples/offline-first","fr/08.examples/4.offline-first",{"title":315,"path":316,"stem":317,"icon":161},"Étude de cas : Conscience réseau","/fr/examples/network-awareness","fr/08.examples/5.network-awareness",{"title":319,"path":320,"stem":321,"icon":126},"Étude de cas : Intégration des hooks","/fr/examples/hooks-integration","fr/08.examples/6.hooks-integration",{"title":323,"path":324,"stem":325,"icon":326},"Étude de cas : Application Todo complète","/fr/examples/complete-todo-app","fr/08.examples/7.complete-todo-app","i-lucide-check-square",{"title":328,"icon":329,"path":330,"stem":331,"children":332,"page":44},"Aide","i-lucide-life-buoy","/fr/help","fr/09.help",[333,338],{"title":334,"path":335,"stem":336,"icon":337},"FAQ","/fr/help/faq","fr/09.help/1.faq","i-lucide-circle-help",{"title":339,"path":340,"stem":341,"icon":101},"Dépannage","/fr/help/troubleshooting","fr/09.help/2.troubleshooting",{"id":343,"title":148,"body":344,"description":2764,"extension":2765,"links":2766,"meta":2767,"navigation":2768,"path":149,"seo":2769,"stem":150,"__hash__":2770},"docs_fr/fr/04.recipes/03.optimistic-updates.md",{"type":345,"value":346,"toc":2750},"minimark",[347,356,359,424,427,432,935,940,1044,1046,1050,2212,2218,2242,2244,2248,2254,2369,2379,2381,2391,2394,2432,2514,2516,2519,2523,2639,2643,2711,2713,2717,2746],[348,349,350,351,355],"p",{},"Une ",[352,353,354],"strong",{},"mise à jour optimiste"," applique un changement d'état local avant la confirmation serveur. Si la requête échoue, les données précédentes sont restaurées.",[348,357,358],{},"Qora fournit trois primitives qui rendent ce pattern simple :",[360,361,362,375],"table",{},[363,364,365],"thead",{},[366,367,368,372],"tr",{},[369,370,371],"th",{},"Méthode",[369,373,374],{},"Description",[376,377,378,401,411],"tbody",{},[366,379,380,387],{},[381,382,383],"td",{},[384,385,386],"code",{},"client.getQueryData\u003CT>(key)",[381,388,389,390,393,394,397,398],{},"Snapshot des données courantes (",[384,391,392],{},"T?","), ou ",[384,395,396],{},"null"," si hors état ",[384,399,400],{},"Success",[366,402,403,408],{},[381,404,405],{},[384,406,407],{},"client.setQueryData\u003CT>(key, data)",[381,409,410],{},"Pousser des données directement dans le cache : tous les widgets abonnés reconstruisent immédiatement",[366,412,413,418],{},[381,414,415],{},[384,416,417],{},"client.restoreQueryData\u003CT>(key, snapshot)",[381,419,420,421,423],{},"Restaurer une valeur de données précédemment snapshotée ; ",[384,422,396],{}," supprime l'entrée",[425,426],"hr",{},[428,429,431],"h2",{"id":430},"le-pattern","Le pattern",[433,434,440],"pre",{"className":435,"code":436,"filename":437,"language":438,"meta":439,"style":439},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","Future\u003Cvoid> updateUserName(BuildContext context, int userId, String newName) async {\n  final client = context.qora;\n  final key = ['users', userId];\n\n  // 1. Snapshot des données courantes pour le rollback\n  final previousUser = client.getQueryData\u003CUser>(key);\n\n  try {\n    // 2. Appliquer la mise à jour optimiste : l'UI reflète le changement instantanément\n    if (previousUser != null) {\n      client.setQueryData\u003CUser>(key, previousUser.copyWith(name: newName));\n    }\n\n    // 3. Déclencher la mutation\n    final updatedUser = await UserApi.updateUser(userId, newName);\n\n    // 4. Confirmer avec la réponse serveur autoritaire\n    client.setQueryData\u003CUser>(key, updatedUser);\n\n    // 5. Invalider les requêtes liées (ex. la liste qui affiche le nom)\n    client.invalidateWhere((key) => key.firstOrNull == 'users');\n  } catch (error) {\n    // 6. Rollback aux données pré-mutation\n    client.restoreQueryData\u003CUser>(key, previousUser);\n\n    if (context.mounted) {\n      ScaffoldMessenger.of(context).showSnackBar(\n        SnackBar(content: Text('Échec de la mise à jour : $error')),\n      );\n    }\n  }\n}\n","update_user.dart","dart","",[384,441,442,500,523,547,554,561,589,594,602,608,626,665,671,676,682,714,719,725,748,753,759,794,806,812,835,840,853,875,910,918,923,929],{"__ignoreMap":439},[443,444,447,451,455,459,462,466,469,472,475,479,482,485,487,490,493,497],"span",{"class":445,"line":446},"line",1,[443,448,450],{"class":449},"sBMFI","Future",[443,452,454],{"class":453},"sTEyZ","\u003C",[443,456,458],{"class":457},"spNyl","void",[443,460,461],{"class":453},"> ",[443,463,465],{"class":464},"s2Zo4","updateUserName",[443,467,468],{"class":453},"(",[443,470,471],{"class":449},"BuildContext",[443,473,474],{"class":453}," context",[443,476,478],{"class":477},"sMK4o",",",[443,480,481],{"class":449}," int",[443,483,484],{"class":453}," userId",[443,486,478],{"class":477},[443,488,489],{"class":449}," String",[443,491,492],{"class":453}," newName) ",[443,494,496],{"class":495},"s7zQu","async",[443,498,499],{"class":453}," {\n",[443,501,503,506,509,512,514,517,520],{"class":445,"line":502},2,[443,504,505],{"class":457},"  final",[443,507,508],{"class":453}," client ",[443,510,511],{"class":477},"=",[443,513,474],{"class":453},[443,515,516],{"class":477},".",[443,518,519],{"class":453},"qora",[443,521,522],{"class":477},";\n",[443,524,526,528,531,533,536,540,542,545],{"class":445,"line":525},3,[443,527,505],{"class":457},[443,529,530],{"class":453}," key ",[443,532,511],{"class":477},[443,534,535],{"class":453}," [",[443,537,539],{"class":538},"sfazB","'users'",[443,541,478],{"class":477},[443,543,544],{"class":453}," userId]",[443,546,522],{"class":477},[443,548,550],{"class":445,"line":549},4,[443,551,553],{"emptyLinePlaceholder":552},true,"\n",[443,555,557],{"class":445,"line":556},5,[443,558,560],{"class":559},"sHwdD","  // 1. Snapshot des données courantes pour le rollback\n",[443,562,564,566,569,571,574,576,579,581,584,587],{"class":445,"line":563},6,[443,565,505],{"class":457},[443,567,568],{"class":453}," previousUser ",[443,570,511],{"class":477},[443,572,573],{"class":453}," client",[443,575,516],{"class":477},[443,577,578],{"class":464},"getQueryData",[443,580,454],{"class":453},[443,582,583],{"class":449},"User",[443,585,586],{"class":453},">(key)",[443,588,522],{"class":477},[443,590,592],{"class":445,"line":591},7,[443,593,553],{"emptyLinePlaceholder":552},[443,595,597,600],{"class":445,"line":596},8,[443,598,599],{"class":495},"  try",[443,601,499],{"class":453},[443,603,605],{"class":445,"line":604},9,[443,606,607],{"class":559},"    // 2. Appliquer la mise à jour optimiste : l'UI reflète le changement instantanément\n",[443,609,611,614,617,620,623],{"class":445,"line":610},10,[443,612,613],{"class":495},"    if",[443,615,616],{"class":453}," (previousUser ",[443,618,619],{"class":477},"!=",[443,621,622],{"class":477}," null",[443,624,625],{"class":453},") {\n",[443,627,629,632,634,637,639,641,644,646,649,651,654,657,660,663],{"class":445,"line":628},11,[443,630,631],{"class":453},"      client",[443,633,516],{"class":477},[443,635,636],{"class":464},"setQueryData",[443,638,454],{"class":453},[443,640,583],{"class":449},[443,642,643],{"class":453},">(key",[443,645,478],{"class":477},[443,647,648],{"class":453}," previousUser",[443,650,516],{"class":477},[443,652,653],{"class":464},"copyWith",[443,655,656],{"class":453},"(name",[443,658,659],{"class":477},":",[443,661,662],{"class":453}," newName))",[443,664,522],{"class":477},[443,666,668],{"class":445,"line":667},12,[443,669,670],{"class":453},"    }\n",[443,672,674],{"class":445,"line":673},13,[443,675,553],{"emptyLinePlaceholder":552},[443,677,679],{"class":445,"line":678},14,[443,680,681],{"class":559},"    // 3. Déclencher la mutation\n",[443,683,685,688,691,693,696,699,701,704,707,709,712],{"class":445,"line":684},15,[443,686,687],{"class":457},"    final",[443,689,690],{"class":453}," updatedUser ",[443,692,511],{"class":477},[443,694,695],{"class":495}," await",[443,697,698],{"class":449}," UserApi",[443,700,516],{"class":477},[443,702,703],{"class":464},"updateUser",[443,705,706],{"class":453},"(userId",[443,708,478],{"class":477},[443,710,711],{"class":453}," newName)",[443,713,522],{"class":477},[443,715,717],{"class":445,"line":716},16,[443,718,553],{"emptyLinePlaceholder":552},[443,720,722],{"class":445,"line":721},17,[443,723,724],{"class":559},"    // 4. Confirmer avec la réponse serveur autoritaire\n",[443,726,728,731,733,735,737,739,741,743,746],{"class":445,"line":727},18,[443,729,730],{"class":453},"    client",[443,732,516],{"class":477},[443,734,636],{"class":464},[443,736,454],{"class":453},[443,738,583],{"class":449},[443,740,643],{"class":453},[443,742,478],{"class":477},[443,744,745],{"class":453}," updatedUser)",[443,747,522],{"class":477},[443,749,751],{"class":445,"line":750},19,[443,752,553],{"emptyLinePlaceholder":552},[443,754,756],{"class":445,"line":755},20,[443,757,758],{"class":559},"    // 5. Invalider les requêtes liées (ex. la liste qui affiche le nom)\n",[443,760,762,764,766,769,772,775,778,780,783,786,789,792],{"class":445,"line":761},21,[443,763,730],{"class":453},[443,765,516],{"class":477},[443,767,768],{"class":464},"invalidateWhere",[443,770,771],{"class":453},"((key) ",[443,773,774],{"class":477},"=>",[443,776,777],{"class":453}," key",[443,779,516],{"class":477},[443,781,782],{"class":453},"firstOrNull ",[443,784,785],{"class":477},"==",[443,787,788],{"class":538}," 'users'",[443,790,791],{"class":453},")",[443,793,522],{"class":477},[443,795,797,800,803],{"class":445,"line":796},22,[443,798,799],{"class":453},"  } ",[443,801,802],{"class":495},"catch",[443,804,805],{"class":453}," (error) {\n",[443,807,809],{"class":445,"line":808},23,[443,810,811],{"class":559},"    // 6. Rollback aux données pré-mutation\n",[443,813,815,817,819,822,824,826,828,830,833],{"class":445,"line":814},24,[443,816,730],{"class":453},[443,818,516],{"class":477},[443,820,821],{"class":464},"restoreQueryData",[443,823,454],{"class":453},[443,825,583],{"class":449},[443,827,643],{"class":453},[443,829,478],{"class":477},[443,831,832],{"class":453}," previousUser)",[443,834,522],{"class":477},[443,836,838],{"class":445,"line":837},25,[443,839,553],{"emptyLinePlaceholder":552},[443,841,843,845,848,850],{"class":445,"line":842},26,[443,844,613],{"class":495},[443,846,847],{"class":453}," (context",[443,849,516],{"class":477},[443,851,852],{"class":453},"mounted) {\n",[443,854,856,859,861,864,867,869,872],{"class":445,"line":855},27,[443,857,858],{"class":449},"      ScaffoldMessenger",[443,860,516],{"class":477},[443,862,863],{"class":464},"of",[443,865,866],{"class":453},"(context)",[443,868,516],{"class":477},[443,870,871],{"class":464},"showSnackBar",[443,873,874],{"class":453},"(\n",[443,876,878,881,884,886,889,891,894,897,901,904,907],{"class":445,"line":877},28,[443,879,880],{"class":449},"        SnackBar",[443,882,883],{"class":453},"(content",[443,885,659],{"class":477},[443,887,888],{"class":449}," Text",[443,890,468],{"class":453},[443,892,893],{"class":538},"'Échec de la mise à jour : ",[443,895,896],{"class":453},"$",[443,898,900],{"class":899},"sHdIc","error",[443,902,903],{"class":538},"'",[443,905,906],{"class":453},"))",[443,908,909],{"class":477},",\n",[443,911,913,916],{"class":445,"line":912},29,[443,914,915],{"class":453},"      )",[443,917,522],{"class":477},[443,919,921],{"class":445,"line":920},30,[443,922,670],{"class":453},[443,924,926],{"class":445,"line":925},31,[443,927,928],{"class":453},"  }\n",[443,930,932],{"class":445,"line":931},32,[443,933,934],{"class":453},"}\n",[936,937,939],"h3",{"id":938},"étape-par-étape","Étape par étape",[360,941,942,955],{},[363,943,944],{},[366,945,946,949,952],{},[369,947,948],{},"Étape",[369,950,951],{},"Appel",[369,953,954],{},"Effet",[376,956,957,976,992,1005,1018,1031],{},[366,958,959,962,967],{},[381,960,961],{},"1",[381,963,964],{},[384,965,966],{},"getQueryData(key)",[381,968,969,970,972,973,975],{},"Retourne la valeur ",[384,971,392],{}," courante, ou ",[384,974,396],{}," si absente du cache",[366,977,978,981,986],{},[381,979,980],{},"2",[381,982,983],{},[384,984,985],{},"setQueryData(key, optimisticData)",[381,987,988,989,991],{},"Cache mis à jour → tous les ",[384,990,108],{}," actifs reconstruisent",[366,993,994,997,1002],{},[381,995,996],{},"3",[381,998,999],{},[384,1000,1001],{},"UserApi.updateUser(...)",[381,1003,1004],{},"Requête réseau en cours",[366,1006,1007,1010,1015],{},[381,1008,1009],{},"4",[381,1011,1012],{},[384,1013,1014],{},"setQueryData(key, serverData)",[381,1016,1017],{},"Cache confirmé avec les données autoritaires du serveur",[366,1019,1020,1023,1028],{},[381,1021,1022],{},"5",[381,1024,1025],{},[384,1026,1027],{},"invalidateWhere(...)",[381,1029,1030],{},"Les requêtes liées (ex. la liste utilisateurs) seront refetchées",[366,1032,1033,1036,1041],{},[381,1034,1035],{},"6",[381,1037,1038],{},[384,1039,1040],{},"restoreQueryData(key, previousUser)",[381,1042,1043],{},"Cache annulé → l'UI revient à l'état pré-mutation",[425,1045],{},[428,1047,1049],{"id":1048},"exemple-complet-écran-dédition-de-profil","Exemple complet : écran d'édition de profil",[433,1051,1054],{"className":435,"code":1052,"filename":1053,"language":438,"meta":439,"style":439},"class EditProfileScreen extends StatefulWidget {\n  final int userId;\n\n  const EditProfileScreen({super.key, required this.userId});\n\n  @override\n  State\u003CEditProfileScreen> createState() => _EditProfileScreenState();\n}\n\nclass _EditProfileScreenState extends State\u003CEditProfileScreen> {\n  late final TextEditingController _nameController;\n  bool _isSaving = false;\n\n  @override\n  void initState() {\n    super.initState();\n    final currentUser = context.qora.getQueryData\u003CUser>(['users', widget.userId]);\n    _nameController = TextEditingController(text: currentUser?.name ?? '');\n  }\n\n  @override\n  void dispose() {\n    _nameController.dispose();\n    super.dispose();\n  }\n\n  Future\u003Cvoid> _save() async {\n    if (_isSaving) return;\n    setState(() => _isSaving = true);\n\n    final client = context.qora;\n    final key = ['users', widget.userId];\n    final previousUser = client.getQueryData\u003CUser>(key);\n\n    try {\n      // Mise à jour optimiste\n      if (previousUser != null) {\n        client.setQueryData\u003CUser>(\n          key,\n          previousUser.copyWith(name: _nameController.text),\n        );\n      }\n\n      final updated = await UserApi.updateUser(\n        widget.userId,\n        _nameController.text,\n      );\n\n      client.setQueryData\u003CUser>(key, updated);\n      client.invalidateWhere((k) => k.firstOrNull == 'users');\n\n      if (mounted) Navigator.pop(context);\n    } catch (error) {\n      client.restoreQueryData\u003CUser>(key, previousUser);\n\n      if (mounted) {\n        ScaffoldMessenger.of(context).showSnackBar(\n          SnackBar(content: Text('Sauvegarde échouée : $error')),\n        );\n        setState(() => _isSaving = false);\n      }\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Modifier le profil'),\n        actions: [\n          TextButton(\n            onPressed: _isSaving ? null : _save,\n            child: _isSaving\n                ? const SizedBox(\n                    width: 16,\n                    height: 16,\n                    child: CircularProgressIndicator(strokeWidth: 2),\n                  )\n                : const Text('Sauvegarder'),\n          ),\n        ],\n      ),\n      body: Padding(\n        padding: const EdgeInsets.all(16),\n        child: TextField(\n          controller: _nameController,\n          decoration: const InputDecoration(labelText: 'Nom'),\n        ),\n      ),\n    );\n  }\n}\n","screens/edit_profile_screen.dart",[384,1055,1056,1072,1082,1086,1116,1120,1125,1153,1157,1161,1179,1195,1208,1212,1216,1227,1241,1281,1314,1318,1322,1326,1335,1349,1361,1365,1369,1389,1401,1422,1426,1442,1465,1488,1493,1501,1507,1521,1538,1546,1569,1577,1583,1588,1609,1622,1635,1642,1647,1669,1698,1703,1723,1733,1754,1759,1767,1785,1812,1819,1840,1845,1850,1855,1860,1865,1881,1892,1905,1927,1938,1946,1969,1980,1993,2007,2019,2042,2048,2067,2075,2083,2090,2103,2130,2143,2155,2180,2187,2194,2202,2207],{"__ignoreMap":439},[443,1057,1058,1061,1064,1067,1070],{"class":445,"line":446},[443,1059,1060],{"class":477},"class",[443,1062,1063],{"class":449}," EditProfileScreen",[443,1065,1066],{"class":477}," extends",[443,1068,1069],{"class":449}," StatefulWidget",[443,1071,499],{"class":453},[443,1073,1074,1076,1078,1080],{"class":445,"line":502},[443,1075,505],{"class":457},[443,1077,481],{"class":449},[443,1079,484],{"class":453},[443,1081,522],{"class":477},[443,1083,1084],{"class":445,"line":525},[443,1085,553],{"emptyLinePlaceholder":552},[443,1087,1088,1091,1093,1096,1098,1101,1103,1106,1109,1111,1114],{"class":445,"line":549},[443,1089,1090],{"class":457},"  const",[443,1092,1063],{"class":449},[443,1094,1095],{"class":453},"({super",[443,1097,516],{"class":477},[443,1099,1100],{"class":453},"key",[443,1102,478],{"class":477},[443,1104,1105],{"class":457}," required",[443,1107,1108],{"class":453}," this",[443,1110,516],{"class":477},[443,1112,1113],{"class":453},"userId})",[443,1115,522],{"class":477},[443,1117,1118],{"class":445,"line":556},[443,1119,553],{"emptyLinePlaceholder":552},[443,1121,1122],{"class":445,"line":563},[443,1123,1124],{"class":457},"  @override\n",[443,1126,1127,1130,1132,1135,1137,1140,1143,1145,1148,1151],{"class":445,"line":591},[443,1128,1129],{"class":449},"  State",[443,1131,454],{"class":453},[443,1133,1134],{"class":449},"EditProfileScreen",[443,1136,461],{"class":453},[443,1138,1139],{"class":464},"createState",[443,1141,1142],{"class":453},"() ",[443,1144,774],{"class":477},[443,1146,1147],{"class":449}," _EditProfileScreenState",[443,1149,1150],{"class":453},"()",[443,1152,522],{"class":477},[443,1154,1155],{"class":445,"line":596},[443,1156,934],{"class":453},[443,1158,1159],{"class":445,"line":604},[443,1160,553],{"emptyLinePlaceholder":552},[443,1162,1163,1165,1167,1169,1172,1174,1176],{"class":445,"line":610},[443,1164,1060],{"class":477},[443,1166,1147],{"class":449},[443,1168,1066],{"class":477},[443,1170,1171],{"class":449}," State",[443,1173,454],{"class":453},[443,1175,1134],{"class":449},[443,1177,1178],{"class":453},"> {\n",[443,1180,1181,1184,1187,1190,1193],{"class":445,"line":628},[443,1182,1183],{"class":457},"  late",[443,1185,1186],{"class":457}," final",[443,1188,1189],{"class":449}," TextEditingController",[443,1191,1192],{"class":453}," _nameController",[443,1194,522],{"class":477},[443,1196,1197,1200,1203,1205],{"class":445,"line":667},[443,1198,1199],{"class":449},"  bool",[443,1201,1202],{"class":453}," _isSaving ",[443,1204,511],{"class":477},[443,1206,1207],{"class":477}," false;\n",[443,1209,1210],{"class":445,"line":673},[443,1211,553],{"emptyLinePlaceholder":552},[443,1213,1214],{"class":445,"line":678},[443,1215,1124],{"class":457},[443,1217,1218,1221,1224],{"class":445,"line":684},[443,1219,1220],{"class":457},"  void",[443,1222,1223],{"class":464}," initState",[443,1225,1226],{"class":453},"() {\n",[443,1228,1229,1232,1234,1237,1239],{"class":445,"line":716},[443,1230,1231],{"class":453},"    super",[443,1233,516],{"class":477},[443,1235,1236],{"class":464},"initState",[443,1238,1150],{"class":453},[443,1240,522],{"class":477},[443,1242,1243,1245,1248,1250,1252,1254,1256,1258,1260,1262,1264,1267,1269,1271,1274,1276,1279],{"class":445,"line":721},[443,1244,687],{"class":457},[443,1246,1247],{"class":453}," currentUser ",[443,1249,511],{"class":477},[443,1251,474],{"class":453},[443,1253,516],{"class":477},[443,1255,519],{"class":453},[443,1257,516],{"class":477},[443,1259,578],{"class":464},[443,1261,454],{"class":453},[443,1263,583],{"class":449},[443,1265,1266],{"class":453},">([",[443,1268,539],{"class":538},[443,1270,478],{"class":477},[443,1272,1273],{"class":453}," widget",[443,1275,516],{"class":477},[443,1277,1278],{"class":453},"userId])",[443,1280,522],{"class":477},[443,1282,1283,1286,1288,1290,1293,1295,1298,1301,1304,1307,1310,1312],{"class":445,"line":727},[443,1284,1285],{"class":453},"    _nameController ",[443,1287,511],{"class":477},[443,1289,1189],{"class":449},[443,1291,1292],{"class":453},"(text",[443,1294,659],{"class":477},[443,1296,1297],{"class":453}," currentUser",[443,1299,1300],{"class":477},"?.",[443,1302,1303],{"class":453},"name ",[443,1305,1306],{"class":477},"??",[443,1308,1309],{"class":538}," ''",[443,1311,791],{"class":453},[443,1313,522],{"class":477},[443,1315,1316],{"class":445,"line":750},[443,1317,928],{"class":453},[443,1319,1320],{"class":445,"line":755},[443,1321,553],{"emptyLinePlaceholder":552},[443,1323,1324],{"class":445,"line":761},[443,1325,1124],{"class":457},[443,1327,1328,1330,1333],{"class":445,"line":796},[443,1329,1220],{"class":457},[443,1331,1332],{"class":464}," dispose",[443,1334,1226],{"class":453},[443,1336,1337,1340,1342,1345,1347],{"class":445,"line":808},[443,1338,1339],{"class":453},"    _nameController",[443,1341,516],{"class":477},[443,1343,1344],{"class":464},"dispose",[443,1346,1150],{"class":453},[443,1348,522],{"class":477},[443,1350,1351,1353,1355,1357,1359],{"class":445,"line":814},[443,1352,1231],{"class":453},[443,1354,516],{"class":477},[443,1356,1344],{"class":464},[443,1358,1150],{"class":453},[443,1360,522],{"class":477},[443,1362,1363],{"class":445,"line":837},[443,1364,928],{"class":453},[443,1366,1367],{"class":445,"line":842},[443,1368,553],{"emptyLinePlaceholder":552},[443,1370,1371,1374,1376,1378,1380,1383,1385,1387],{"class":445,"line":855},[443,1372,1373],{"class":449},"  Future",[443,1375,454],{"class":453},[443,1377,458],{"class":457},[443,1379,461],{"class":453},[443,1381,1382],{"class":464},"_save",[443,1384,1142],{"class":453},[443,1386,496],{"class":495},[443,1388,499],{"class":453},[443,1390,1391,1393,1396,1399],{"class":445,"line":877},[443,1392,613],{"class":495},[443,1394,1395],{"class":453}," (_isSaving) ",[443,1397,1398],{"class":495},"return",[443,1400,522],{"class":477},[443,1402,1403,1406,1409,1411,1413,1415,1418,1420],{"class":445,"line":912},[443,1404,1405],{"class":464},"    setState",[443,1407,1408],{"class":453},"(() ",[443,1410,774],{"class":477},[443,1412,1202],{"class":453},[443,1414,511],{"class":477},[443,1416,1417],{"class":477}," true",[443,1419,791],{"class":453},[443,1421,522],{"class":477},[443,1423,1424],{"class":445,"line":920},[443,1425,553],{"emptyLinePlaceholder":552},[443,1427,1428,1430,1432,1434,1436,1438,1440],{"class":445,"line":925},[443,1429,687],{"class":457},[443,1431,508],{"class":453},[443,1433,511],{"class":477},[443,1435,474],{"class":453},[443,1437,516],{"class":477},[443,1439,519],{"class":453},[443,1441,522],{"class":477},[443,1443,1444,1446,1448,1450,1452,1454,1456,1458,1460,1463],{"class":445,"line":931},[443,1445,687],{"class":457},[443,1447,530],{"class":453},[443,1449,511],{"class":477},[443,1451,535],{"class":453},[443,1453,539],{"class":538},[443,1455,478],{"class":477},[443,1457,1273],{"class":453},[443,1459,516],{"class":477},[443,1461,1462],{"class":453},"userId]",[443,1464,522],{"class":477},[443,1466,1468,1470,1472,1474,1476,1478,1480,1482,1484,1486],{"class":445,"line":1467},33,[443,1469,687],{"class":457},[443,1471,568],{"class":453},[443,1473,511],{"class":477},[443,1475,573],{"class":453},[443,1477,516],{"class":477},[443,1479,578],{"class":464},[443,1481,454],{"class":453},[443,1483,583],{"class":449},[443,1485,586],{"class":453},[443,1487,522],{"class":477},[443,1489,1491],{"class":445,"line":1490},34,[443,1492,553],{"emptyLinePlaceholder":552},[443,1494,1496,1499],{"class":445,"line":1495},35,[443,1497,1498],{"class":495},"    try",[443,1500,499],{"class":453},[443,1502,1504],{"class":445,"line":1503},36,[443,1505,1506],{"class":559},"      // Mise à jour optimiste\n",[443,1508,1510,1513,1515,1517,1519],{"class":445,"line":1509},37,[443,1511,1512],{"class":495},"      if",[443,1514,616],{"class":453},[443,1516,619],{"class":477},[443,1518,622],{"class":477},[443,1520,625],{"class":453},[443,1522,1524,1527,1529,1531,1533,1535],{"class":445,"line":1523},38,[443,1525,1526],{"class":453},"        client",[443,1528,516],{"class":477},[443,1530,636],{"class":464},[443,1532,454],{"class":453},[443,1534,583],{"class":449},[443,1536,1537],{"class":453},">(\n",[443,1539,1541,1544],{"class":445,"line":1540},39,[443,1542,1543],{"class":453},"          key",[443,1545,909],{"class":477},[443,1547,1549,1552,1554,1556,1558,1560,1562,1564,1567],{"class":445,"line":1548},40,[443,1550,1551],{"class":453},"          previousUser",[443,1553,516],{"class":477},[443,1555,653],{"class":464},[443,1557,656],{"class":453},[443,1559,659],{"class":477},[443,1561,1192],{"class":453},[443,1563,516],{"class":477},[443,1565,1566],{"class":453},"text)",[443,1568,909],{"class":477},[443,1570,1572,1575],{"class":445,"line":1571},41,[443,1573,1574],{"class":453},"        )",[443,1576,522],{"class":477},[443,1578,1580],{"class":445,"line":1579},42,[443,1581,1582],{"class":453},"      }\n",[443,1584,1586],{"class":445,"line":1585},43,[443,1587,553],{"emptyLinePlaceholder":552},[443,1589,1591,1594,1597,1599,1601,1603,1605,1607],{"class":445,"line":1590},44,[443,1592,1593],{"class":457},"      final",[443,1595,1596],{"class":453}," updated ",[443,1598,511],{"class":477},[443,1600,695],{"class":495},[443,1602,698],{"class":449},[443,1604,516],{"class":477},[443,1606,703],{"class":464},[443,1608,874],{"class":453},[443,1610,1612,1615,1617,1620],{"class":445,"line":1611},45,[443,1613,1614],{"class":453},"        widget",[443,1616,516],{"class":477},[443,1618,1619],{"class":453},"userId",[443,1621,909],{"class":477},[443,1623,1625,1628,1630,1633],{"class":445,"line":1624},46,[443,1626,1627],{"class":453},"        _nameController",[443,1629,516],{"class":477},[443,1631,1632],{"class":453},"text",[443,1634,909],{"class":477},[443,1636,1638,1640],{"class":445,"line":1637},47,[443,1639,915],{"class":453},[443,1641,522],{"class":477},[443,1643,1645],{"class":445,"line":1644},48,[443,1646,553],{"emptyLinePlaceholder":552},[443,1648,1650,1652,1654,1656,1658,1660,1662,1664,1667],{"class":445,"line":1649},49,[443,1651,631],{"class":453},[443,1653,516],{"class":477},[443,1655,636],{"class":464},[443,1657,454],{"class":453},[443,1659,583],{"class":449},[443,1661,643],{"class":453},[443,1663,478],{"class":477},[443,1665,1666],{"class":453}," updated)",[443,1668,522],{"class":477},[443,1670,1672,1674,1676,1678,1681,1683,1686,1688,1690,1692,1694,1696],{"class":445,"line":1671},50,[443,1673,631],{"class":453},[443,1675,516],{"class":477},[443,1677,768],{"class":464},[443,1679,1680],{"class":453},"((k) ",[443,1682,774],{"class":477},[443,1684,1685],{"class":453}," k",[443,1687,516],{"class":477},[443,1689,782],{"class":453},[443,1691,785],{"class":477},[443,1693,788],{"class":538},[443,1695,791],{"class":453},[443,1697,522],{"class":477},[443,1699,1701],{"class":445,"line":1700},51,[443,1702,553],{"emptyLinePlaceholder":552},[443,1704,1706,1708,1711,1714,1716,1719,1721],{"class":445,"line":1705},52,[443,1707,1512],{"class":495},[443,1709,1710],{"class":453}," (mounted) ",[443,1712,1713],{"class":449},"Navigator",[443,1715,516],{"class":477},[443,1717,1718],{"class":464},"pop",[443,1720,866],{"class":453},[443,1722,522],{"class":477},[443,1724,1726,1729,1731],{"class":445,"line":1725},53,[443,1727,1728],{"class":453},"    } ",[443,1730,802],{"class":495},[443,1732,805],{"class":453},[443,1734,1736,1738,1740,1742,1744,1746,1748,1750,1752],{"class":445,"line":1735},54,[443,1737,631],{"class":453},[443,1739,516],{"class":477},[443,1741,821],{"class":464},[443,1743,454],{"class":453},[443,1745,583],{"class":449},[443,1747,643],{"class":453},[443,1749,478],{"class":477},[443,1751,832],{"class":453},[443,1753,522],{"class":477},[443,1755,1757],{"class":445,"line":1756},55,[443,1758,553],{"emptyLinePlaceholder":552},[443,1760,1762,1764],{"class":445,"line":1761},56,[443,1763,1512],{"class":495},[443,1765,1766],{"class":453}," (mounted) {\n",[443,1768,1770,1773,1775,1777,1779,1781,1783],{"class":445,"line":1769},57,[443,1771,1772],{"class":449},"        ScaffoldMessenger",[443,1774,516],{"class":477},[443,1776,863],{"class":464},[443,1778,866],{"class":453},[443,1780,516],{"class":477},[443,1782,871],{"class":464},[443,1784,874],{"class":453},[443,1786,1788,1791,1793,1795,1797,1799,1802,1804,1806,1808,1810],{"class":445,"line":1787},58,[443,1789,1790],{"class":449},"          SnackBar",[443,1792,883],{"class":453},[443,1794,659],{"class":477},[443,1796,888],{"class":449},[443,1798,468],{"class":453},[443,1800,1801],{"class":538},"'Sauvegarde échouée : ",[443,1803,896],{"class":453},[443,1805,900],{"class":899},[443,1807,903],{"class":538},[443,1809,906],{"class":453},[443,1811,909],{"class":477},[443,1813,1815,1817],{"class":445,"line":1814},59,[443,1816,1574],{"class":453},[443,1818,522],{"class":477},[443,1820,1822,1825,1827,1829,1831,1833,1836,1838],{"class":445,"line":1821},60,[443,1823,1824],{"class":464},"        setState",[443,1826,1408],{"class":453},[443,1828,774],{"class":477},[443,1830,1202],{"class":453},[443,1832,511],{"class":477},[443,1834,1835],{"class":477}," false",[443,1837,791],{"class":453},[443,1839,522],{"class":477},[443,1841,1843],{"class":445,"line":1842},61,[443,1844,1582],{"class":453},[443,1846,1848],{"class":445,"line":1847},62,[443,1849,670],{"class":453},[443,1851,1853],{"class":445,"line":1852},63,[443,1854,928],{"class":453},[443,1856,1858],{"class":445,"line":1857},64,[443,1859,553],{"emptyLinePlaceholder":552},[443,1861,1863],{"class":445,"line":1862},65,[443,1864,1124],{"class":457},[443,1866,1868,1871,1874,1876,1878],{"class":445,"line":1867},66,[443,1869,1870],{"class":449},"  Widget",[443,1872,1873],{"class":464}," build",[443,1875,468],{"class":453},[443,1877,471],{"class":449},[443,1879,1880],{"class":453}," context) {\n",[443,1882,1884,1887,1890],{"class":445,"line":1883},67,[443,1885,1886],{"class":495},"    return",[443,1888,1889],{"class":449}," Scaffold",[443,1891,874],{"class":453},[443,1893,1895,1898,1900,1903],{"class":445,"line":1894},68,[443,1896,1897],{"class":453},"      appBar",[443,1899,659],{"class":477},[443,1901,1902],{"class":449}," AppBar",[443,1904,874],{"class":453},[443,1906,1908,1911,1913,1916,1918,1920,1923,1925],{"class":445,"line":1907},69,[443,1909,1910],{"class":453},"        title",[443,1912,659],{"class":477},[443,1914,1915],{"class":457}," const",[443,1917,888],{"class":449},[443,1919,468],{"class":453},[443,1921,1922],{"class":538},"'Modifier le profil'",[443,1924,791],{"class":453},[443,1926,909],{"class":477},[443,1928,1930,1933,1935],{"class":445,"line":1929},70,[443,1931,1932],{"class":453},"        actions",[443,1934,659],{"class":477},[443,1936,1937],{"class":453}," [\n",[443,1939,1941,1944],{"class":445,"line":1940},71,[443,1942,1943],{"class":449},"          TextButton",[443,1945,874],{"class":453},[443,1947,1949,1952,1954,1956,1959,1961,1964,1967],{"class":445,"line":1948},72,[443,1950,1951],{"class":453},"            onPressed",[443,1953,659],{"class":477},[443,1955,1202],{"class":453},[443,1957,1958],{"class":477},"?",[443,1960,622],{"class":477},[443,1962,1963],{"class":477}," :",[443,1965,1966],{"class":453}," _save",[443,1968,909],{"class":477},[443,1970,1972,1975,1977],{"class":445,"line":1971},73,[443,1973,1974],{"class":453},"            child",[443,1976,659],{"class":477},[443,1978,1979],{"class":453}," _isSaving\n",[443,1981,1983,1986,1988,1991],{"class":445,"line":1982},74,[443,1984,1985],{"class":477},"                ?",[443,1987,1915],{"class":457},[443,1989,1990],{"class":449}," SizedBox",[443,1992,874],{"class":453},[443,1994,1996,1999,2001,2005],{"class":445,"line":1995},75,[443,1997,1998],{"class":453},"                    width",[443,2000,659],{"class":477},[443,2002,2004],{"class":2003},"sbssI"," 16",[443,2006,909],{"class":477},[443,2008,2010,2013,2015,2017],{"class":445,"line":2009},76,[443,2011,2012],{"class":453},"                    height",[443,2014,659],{"class":477},[443,2016,2004],{"class":2003},[443,2018,909],{"class":477},[443,2020,2022,2025,2027,2030,2033,2035,2038,2040],{"class":445,"line":2021},77,[443,2023,2024],{"class":453},"                    child",[443,2026,659],{"class":477},[443,2028,2029],{"class":449}," CircularProgressIndicator",[443,2031,2032],{"class":453},"(strokeWidth",[443,2034,659],{"class":477},[443,2036,2037],{"class":2003}," 2",[443,2039,791],{"class":453},[443,2041,909],{"class":477},[443,2043,2045],{"class":445,"line":2044},78,[443,2046,2047],{"class":453},"                  )\n",[443,2049,2051,2054,2056,2058,2060,2063,2065],{"class":445,"line":2050},79,[443,2052,2053],{"class":477},"                :",[443,2055,1915],{"class":457},[443,2057,888],{"class":449},[443,2059,468],{"class":453},[443,2061,2062],{"class":538},"'Sauvegarder'",[443,2064,791],{"class":453},[443,2066,909],{"class":477},[443,2068,2070,2073],{"class":445,"line":2069},80,[443,2071,2072],{"class":453},"          )",[443,2074,909],{"class":477},[443,2076,2078,2081],{"class":445,"line":2077},81,[443,2079,2080],{"class":453},"        ]",[443,2082,909],{"class":477},[443,2084,2086,2088],{"class":445,"line":2085},82,[443,2087,915],{"class":453},[443,2089,909],{"class":477},[443,2091,2093,2096,2098,2101],{"class":445,"line":2092},83,[443,2094,2095],{"class":453},"      body",[443,2097,659],{"class":477},[443,2099,2100],{"class":449}," Padding",[443,2102,874],{"class":453},[443,2104,2106,2109,2111,2113,2116,2118,2121,2123,2126,2128],{"class":445,"line":2105},84,[443,2107,2108],{"class":453},"        padding",[443,2110,659],{"class":477},[443,2112,1915],{"class":457},[443,2114,2115],{"class":449}," EdgeInsets",[443,2117,516],{"class":477},[443,2119,2120],{"class":464},"all",[443,2122,468],{"class":453},[443,2124,2125],{"class":2003},"16",[443,2127,791],{"class":453},[443,2129,909],{"class":477},[443,2131,2133,2136,2138,2141],{"class":445,"line":2132},85,[443,2134,2135],{"class":453},"        child",[443,2137,659],{"class":477},[443,2139,2140],{"class":449}," TextField",[443,2142,874],{"class":453},[443,2144,2146,2149,2151,2153],{"class":445,"line":2145},86,[443,2147,2148],{"class":453},"          controller",[443,2150,659],{"class":477},[443,2152,1192],{"class":453},[443,2154,909],{"class":477},[443,2156,2158,2161,2163,2165,2168,2171,2173,2176,2178],{"class":445,"line":2157},87,[443,2159,2160],{"class":453},"          decoration",[443,2162,659],{"class":477},[443,2164,1915],{"class":457},[443,2166,2167],{"class":449}," InputDecoration",[443,2169,2170],{"class":453},"(labelText",[443,2172,659],{"class":477},[443,2174,2175],{"class":538}," 'Nom'",[443,2177,791],{"class":453},[443,2179,909],{"class":477},[443,2181,2183,2185],{"class":445,"line":2182},88,[443,2184,1574],{"class":453},[443,2186,909],{"class":477},[443,2188,2190,2192],{"class":445,"line":2189},89,[443,2191,915],{"class":453},[443,2193,909],{"class":477},[443,2195,2197,2200],{"class":445,"line":2196},90,[443,2198,2199],{"class":453},"    )",[443,2201,522],{"class":477},[443,2203,2205],{"class":445,"line":2204},91,[443,2206,928],{"class":453},[443,2208,2210],{"class":445,"line":2209},92,[443,2211,934],{"class":453},[348,2213,2214,2215,1963],{},"Quand l'utilisateur appuie sur ",[352,2216,2217],{},"Sauvegarder",[2219,2220,2221,2233,2236,2239],"ol",{},[2222,2223,2224,2225,2228,2229,2232],"li",{},"L'",[384,2226,2227],{},"UserDetailScreen"," (qui utilise ",[384,2230,2231],{},"QoraBuilder\u003CUser>",") reflète immédiatement le nouveau nom : sans spinner, sans délai.",[2222,2234,2235],{},"La requête réseau se déclenche en arrière-plan.",[2222,2237,2238],{},"En cas de succès, la réponse serveur confirme les données.",[2222,2240,2241],{},"En cas d'échec, le nom revient à ce qu'il était avant l'appui.",[425,2243],{},[428,2245,2247],{"id":2246},"invalider-les-requêtes-liées","Invalider les requêtes liées",[348,2249,2250,2251,2253],{},"Après une mutation réussie, il est généralement souhaitable d'invalider les requêtes liées pour rafraîchir les vues de liste périmées. Utiliser ",[384,2252,768],{}," avec un prédicat :",[433,2255,2257],{"className":435,"code":2256,"filename":437,"language":438,"meta":439,"style":439},"// Invalider l'utilisateur spécifique ET la liste des utilisateurs\nclient.invalidateWhere((key) => key.firstOrNull == 'users');\n\n// Plus ciblé : uniquement la liste, pas l'entrée individuelle\nclient.invalidateWhere((key) => key.length == 1 && key.firstOrNull == 'users');\n\n// Ou invalider la clé exacte\nclient.invalidate(['users']);\n",[384,2258,2259,2264,2291,2295,2300,2341,2345,2350],{"__ignoreMap":439},[443,2260,2261],{"class":445,"line":446},[443,2262,2263],{"class":559},"// Invalider l'utilisateur spécifique ET la liste des utilisateurs\n",[443,2265,2266,2269,2271,2273,2275,2277,2279,2281,2283,2285,2287,2289],{"class":445,"line":502},[443,2267,2268],{"class":453},"client",[443,2270,516],{"class":477},[443,2272,768],{"class":464},[443,2274,771],{"class":453},[443,2276,774],{"class":477},[443,2278,777],{"class":453},[443,2280,516],{"class":477},[443,2282,782],{"class":453},[443,2284,785],{"class":477},[443,2286,788],{"class":538},[443,2288,791],{"class":453},[443,2290,522],{"class":477},[443,2292,2293],{"class":445,"line":525},[443,2294,553],{"emptyLinePlaceholder":552},[443,2296,2297],{"class":445,"line":549},[443,2298,2299],{"class":559},"// Plus ciblé : uniquement la liste, pas l'entrée individuelle\n",[443,2301,2302,2304,2306,2308,2310,2312,2314,2316,2319,2321,2324,2327,2329,2331,2333,2335,2337,2339],{"class":445,"line":556},[443,2303,2268],{"class":453},[443,2305,516],{"class":477},[443,2307,768],{"class":464},[443,2309,771],{"class":453},[443,2311,774],{"class":477},[443,2313,777],{"class":453},[443,2315,516],{"class":477},[443,2317,2318],{"class":453},"length ",[443,2320,785],{"class":477},[443,2322,2323],{"class":2003}," 1",[443,2325,2326],{"class":477}," &&",[443,2328,777],{"class":453},[443,2330,516],{"class":477},[443,2332,782],{"class":453},[443,2334,785],{"class":477},[443,2336,788],{"class":538},[443,2338,791],{"class":453},[443,2340,522],{"class":477},[443,2342,2343],{"class":445,"line":563},[443,2344,553],{"emptyLinePlaceholder":552},[443,2346,2347],{"class":445,"line":591},[443,2348,2349],{"class":559},"// Ou invalider la clé exacte\n",[443,2351,2352,2354,2356,2359,2362,2364,2367],{"class":445,"line":596},[443,2353,2268],{"class":453},[443,2355,516],{"class":477},[443,2357,2358],{"class":464},"invalidate",[443,2360,2361],{"class":453},"([",[443,2363,539],{"class":538},[443,2365,2366],{"class":453},"])",[443,2368,522],{"class":477},[348,2370,2371,2372,2374,2375,2378],{},"Les widgets ",[384,2373,108],{}," actifs pour toute clé correspondante reçoivent ",[384,2376,2377],{},"Loading(previousData: data)"," et relancent immédiatement un fetch. Comme les données précédentes sont portées, il n'y a pas de flash de contenu vide.",[425,2380],{},[428,2382,2384,2385,2387,2388,2390],{"id":2383},"pourquoi-restorequerydata-plutôt-que-setquerydata","Pourquoi ",[384,2386,821],{}," plutôt que ",[384,2389,636],{}," ?",[348,2392,2393],{},"Les deux méthodes écrivent des données dans le cache. La différence réside dans la gestion du null :",[2395,2396,2397,2409],"ul",{},[2222,2398,2399,2402,2403,2406,2407,516],{},[384,2400,2401],{},"setQueryData\u003CT>(key, data)",": requiert une valeur ",[384,2404,2405],{},"T"," non nulle ; produit toujours un état ",[384,2408,400],{},[2222,2410,2411,2414,2415,2417,2418,2421,2422,2424,2425,2428,2429,2431],{},[384,2412,2413],{},"restoreQueryData\u003CT>(key, snapshot)",": accepte ",[384,2416,392],{}," ; quand ",[384,2419,2420],{},"snapshot"," est ",[384,2423,396],{},", appelle ",[384,2426,2427],{},"removeQuery(key)"," au lieu d'écrire. Cela rend le rollback sûr quand la requête n'avait pas de données antérieures : aucun état ",[384,2430,400],{}," orphelin n'est laissé derrière.",[433,2433,2436],{"className":435,"code":2434,"filename":2435,"language":438,"meta":439,"style":439},"// Correct : gère le cas null (requête sans données antérieures)\nclient.restoreQueryData\u003CUser>(key, previousUser); // null → removeQuery\n\n// Attention : Équivalent uniquement quand previousUser est garanti non-null\nif (previousUser != null) {\n  client.setQueryData\u003CUser>(key, previousUser);\n}\n","rollback.dart",[384,2437,2438,2443,2467,2471,2476,2489,2510],{"__ignoreMap":439},[443,2439,2440],{"class":445,"line":446},[443,2441,2442],{"class":559},"// Correct : gère le cas null (requête sans données antérieures)\n",[443,2444,2445,2447,2449,2451,2453,2455,2457,2459,2461,2464],{"class":445,"line":502},[443,2446,2268],{"class":453},[443,2448,516],{"class":477},[443,2450,821],{"class":464},[443,2452,454],{"class":453},[443,2454,583],{"class":449},[443,2456,643],{"class":453},[443,2458,478],{"class":477},[443,2460,832],{"class":453},[443,2462,2463],{"class":477},";",[443,2465,2466],{"class":559}," // null → removeQuery\n",[443,2468,2469],{"class":445,"line":525},[443,2470,553],{"emptyLinePlaceholder":552},[443,2472,2473],{"class":445,"line":549},[443,2474,2475],{"class":559},"// Attention : Équivalent uniquement quand previousUser est garanti non-null\n",[443,2477,2478,2481,2483,2485,2487],{"class":445,"line":556},[443,2479,2480],{"class":495},"if",[443,2482,616],{"class":453},[443,2484,619],{"class":477},[443,2486,622],{"class":477},[443,2488,625],{"class":453},[443,2490,2491,2494,2496,2498,2500,2502,2504,2506,2508],{"class":445,"line":563},[443,2492,2493],{"class":453},"  client",[443,2495,516],{"class":477},[443,2497,636],{"class":464},[443,2499,454],{"class":453},[443,2501,583],{"class":449},[443,2503,643],{"class":453},[443,2505,478],{"class":477},[443,2507,832],{"class":453},[443,2509,522],{"class":477},[443,2511,2512],{"class":445,"line":591},[443,2513,934],{"class":453},[425,2515],{},[428,2517,133],{"id":2518},"bonnes-pratiques",[936,2520,2522],{"id":2521},"à-faire","À faire",[433,2524,2527],{"className":435,"code":2525,"filename":2526,"language":438,"meta":439,"style":439},"// Toujours faire un snapshot avant de muter\nfinal previousUser = client.getQueryData\u003CUser>(key);\n\n// Appliquer la mise à jour optimiste uniquement si les données existent\nif (previousUser != null) {\n  client.setQueryData(key, optimisticData);\n}\n\n// Toujours restaurer sur tout chemin d'erreur\n} catch (_) {\n  client.restoreQueryData(key, previousUser);\n}\n","update.dart",[384,2528,2529,2534,2557,2561,2566,2578,2596,2600,2604,2609,2619,2635],{"__ignoreMap":439},[443,2530,2531],{"class":445,"line":446},[443,2532,2533],{"class":559},"// Toujours faire un snapshot avant de muter\n",[443,2535,2536,2539,2541,2543,2545,2547,2549,2551,2553,2555],{"class":445,"line":502},[443,2537,2538],{"class":457},"final",[443,2540,568],{"class":453},[443,2542,511],{"class":477},[443,2544,573],{"class":453},[443,2546,516],{"class":477},[443,2548,578],{"class":464},[443,2550,454],{"class":453},[443,2552,583],{"class":449},[443,2554,586],{"class":453},[443,2556,522],{"class":477},[443,2558,2559],{"class":445,"line":525},[443,2560,553],{"emptyLinePlaceholder":552},[443,2562,2563],{"class":445,"line":549},[443,2564,2565],{"class":559},"// Appliquer la mise à jour optimiste uniquement si les données existent\n",[443,2567,2568,2570,2572,2574,2576],{"class":445,"line":556},[443,2569,2480],{"class":495},[443,2571,616],{"class":453},[443,2573,619],{"class":477},[443,2575,622],{"class":477},[443,2577,625],{"class":453},[443,2579,2580,2582,2584,2586,2589,2591,2594],{"class":445,"line":563},[443,2581,2493],{"class":453},[443,2583,516],{"class":477},[443,2585,636],{"class":464},[443,2587,2588],{"class":453},"(key",[443,2590,478],{"class":477},[443,2592,2593],{"class":453}," optimisticData)",[443,2595,522],{"class":477},[443,2597,2598],{"class":445,"line":591},[443,2599,934],{"class":453},[443,2601,2602],{"class":445,"line":596},[443,2603,553],{"emptyLinePlaceholder":552},[443,2605,2606],{"class":445,"line":604},[443,2607,2608],{"class":559},"// Toujours restaurer sur tout chemin d'erreur\n",[443,2610,2611,2614,2616],{"class":445,"line":610},[443,2612,2613],{"class":453},"} ",[443,2615,802],{"class":495},[443,2617,2618],{"class":453}," (_) {\n",[443,2620,2621,2623,2625,2627,2629,2631,2633],{"class":445,"line":628},[443,2622,2493],{"class":453},[443,2624,516],{"class":477},[443,2626,821],{"class":464},[443,2628,2588],{"class":453},[443,2630,478],{"class":477},[443,2632,832],{"class":453},[443,2634,522],{"class":477},[443,2636,2637],{"class":445,"line":667},[443,2638,934],{"class":453},[936,2640,2642],{"id":2641},"à-éviter","À éviter",[433,2644,2646],{"className":435,"code":2645,"filename":2526,"language":438,"meta":439,"style":439},"// Ne pas omettre le snapshot : impossible de faire un rollback\nclient.setQueryData(key, optimisticData);\nawait api.update(data); // si cela lève une exception, pas de rollback possible\n\n// Ne pas ignorer l'erreur : toujours informer l'utilisateur\n} catch (_) {} // Incorrect : Un échec silencieux est pire qu'aucune mise à jour optimiste\n",[384,2647,2648,2653,2669,2690,2694,2699],{"__ignoreMap":439},[443,2649,2650],{"class":445,"line":446},[443,2651,2652],{"class":559},"// Ne pas omettre le snapshot : impossible de faire un rollback\n",[443,2654,2655,2657,2659,2661,2663,2665,2667],{"class":445,"line":502},[443,2656,2268],{"class":453},[443,2658,516],{"class":477},[443,2660,636],{"class":464},[443,2662,2588],{"class":453},[443,2664,478],{"class":477},[443,2666,2593],{"class":453},[443,2668,522],{"class":477},[443,2670,2671,2674,2677,2679,2682,2685,2687],{"class":445,"line":525},[443,2672,2673],{"class":495},"await",[443,2675,2676],{"class":453}," api",[443,2678,516],{"class":477},[443,2680,2681],{"class":464},"update",[443,2683,2684],{"class":453},"(data)",[443,2686,2463],{"class":477},[443,2688,2689],{"class":559}," // si cela lève une exception, pas de rollback possible\n",[443,2691,2692],{"class":445,"line":549},[443,2693,553],{"emptyLinePlaceholder":552},[443,2695,2696],{"class":445,"line":556},[443,2697,2698],{"class":559},"// Ne pas ignorer l'erreur : toujours informer l'utilisateur\n",[443,2700,2701,2703,2705,2708],{"class":445,"line":563},[443,2702,2613],{"class":453},[443,2704,802],{"class":495},[443,2706,2707],{"class":453}," (_) {} ",[443,2709,2710],{"class":559},"// Incorrect : Un échec silencieux est pire qu'aucune mise à jour optimiste\n",[425,2712],{},[428,2714,2716],{"id":2715},"étapes-suivantes","Étapes suivantes",[2395,2718,2719,2726,2740],{},[2222,2720,2721,2725],{},[2722,2723,21],"a",{"href":2724},"../getting-started/quick-start"," : Écrans de liste et de détail sans mutations",[2222,2727,2728,2732,2733,2735,2736,2735,2738],{},[2722,2729,2731],{"href":2730},"../api-reference/qora-client","API QoraClient"," : Référence de ",[384,2734,636],{},", ",[384,2737,578],{},[384,2739,821],{},[2222,2741,2742,2745],{},[2722,2743,62],{"href":2744},"../core-concepts/query-states"," : Comprendre la machine d'état qui rend le rollback prévisible",[2747,2748,2749],"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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .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}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":439,"searchDepth":502,"depth":502,"links":2751},[2752,2755,2756,2757,2759,2763],{"id":430,"depth":502,"text":431,"children":2753},[2754],{"id":938,"depth":525,"text":939},{"id":1048,"depth":502,"text":1049},{"id":2246,"depth":502,"text":2247},{"id":2383,"depth":502,"text":2758},"Pourquoi restoreQueryData plutôt que setQueryData ?",{"id":2518,"depth":502,"text":133,"children":2760},[2761,2762],{"id":2521,"depth":525,"text":2522},{"id":2641,"depth":525,"text":2642},{"id":2715,"depth":502,"text":2716},"Mettre à jour l'UI instantanément pendant que les mutations sont en cours, et effectuer un rollback sécurisé en cas d'échec : sans bibliothèques supplémentaires.","md",null,{},{"icon":151},{"title":148,"description":2764},"iOr5zNIMcrpkeVG_X0ZMaQYH65RBAUuN-OJ5PrOhlhA",[2772,2774],{"title":144,"path":145,"stem":146,"description":2773,"icon":85,"children":-1},"Effectuer des opérations d'écriture (POST, PUT, DELETE) avec un support complet du cycle de vie : mises à jour optimistes, rollback automatique, retry et observabilité DevTools.",{"title":153,"path":154,"stem":155,"description":2775,"icon":156,"children":-1},"Persister les résultats des requêtes sur disque et les restaurer au démarrage : donnant à l'application une couche de données instantanée qui fonctionne entièrement hors-ligne.",1794040404295]