[{"data":1,"prerenderedAt":2390},["ShallowReactive",2],{"navigation_docs_fr":3,"-fr-examples-hooks-integration":342,"-fr-examples-hooks-integration-surround":2385},[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":319,"body":344,"description":2376,"extension":2377,"links":2378,"meta":2379,"navigation":2380,"path":320,"seo":2381,"stem":321,"__hash__":2384},"docs_fr/fr/08.examples/6.hooks-integration.md",{"type":345,"value":346,"toc":2358},"minimark",[347,352,364,382,385,389,516,518,522,557,567,588,590,594,601,619,1405,1417,1423,1430,1478,1517,1523,1534,1704,1724,1731,1741,2191,2198,2200,2204,2210,2219,2221,2225,2311,2313,2317,2354],[348,349,351],"h2",{"id":350},"objectif","Objectif",[353,354,355,359,360,363],"p",{},[356,357,358],"strong",{},"Contexte",": ",[361,362,108],"code",{}," introduit des callbacks de builder imbriqués sur les écrans qui combinent lecture et écriture. Cette structure augmente la profondeur d'indentation et réduit la maintenabilité sur les vues complexes.",[353,365,366,369,370,373,374,377,378,381],{},[361,367,368],{},"qora_hooks"," aplatit cette structure. ",[361,371,372],{},"useQuery"," et ",[361,375,376],{},"useMutation"," sont déclarés en haut de ",[361,379,380],{},"build()",", et l'arbre de widgets est rendu depuis des valeurs simples. La sémantique du cache et la déduplication restent identiques.",[383,384],"hr",{},[348,386,388],{"id":387},"fonctionnalités-démontrées","Fonctionnalités démontrées",[390,391,392,405,436,458,476,495,507],"ul",{},[393,394,395,400,401,404],"li",{},[356,396,397],{},[361,398,399],{},"useQuery\u003CT>",": s'abonne à une requête, retourne ",[361,402,403],{},"QoraState\u003CT>"," comme valeur simple ; re-rend à chaque changement d'état",[393,406,407,412,413,416,417,420,421,420,424,420,427,420,430,420,433],{},[356,408,409],{},[361,410,411],{},"useMutation\u003CTData, TVariables>",": retourne un ",[361,414,415],{},"MutationHandle"," avec ",[361,418,419],{},"mutate",", ",[361,422,423],{},"mutateAsync",[361,425,426],{},"isPending",[361,428,429],{},"isError",[361,431,432],{},"data",[361,434,435],{},"reset",[393,437,438,412,443,416,446,420,449,420,452,420,455],{},[356,439,440],{},[361,441,442],{},"useInfiniteQuery\u003CTData, TPageParam>",[361,444,445],{},"InfiniteQueryHandle",[361,447,448],{},"pages",[361,450,451],{},"fetchNextPage",[361,453,454],{},"hasNextPage",[361,456,457],{},"isFetchingNextPage",[393,459,460,465,466,468,469,420,472,475],{},[356,461,462],{},[361,463,464],{},"useQueryClient",": retourne le ",[361,467,202],{}," le plus proche pour les opérations impératives (",[361,470,471],{},"invalidate",[361,473,474],{},"setQueryData",")",[393,477,478,359,483,486,487,490,491,494],{},[356,479,480],{},[361,481,482],{},"useIsFetching",[361,484,485],{},"bool"," global ",[361,488,489],{},"true"," tant qu'une requête a une demande en vol; pilote un ",[361,492,493],{},"LinearProgressIndicator"," au niveau racine sans couplage à des requêtes individuelles",[393,496,497,359,502,486,504,506],{},[356,498,499],{},[361,500,501],{},"useIsMutating",[361,503,485],{},[361,505,489],{}," tant qu'une mutation est en attente; désactive les boutons de soumission à l'échelle de l'app",[393,508,509,512,513,515],{},[356,510,511],{},"Composition de hooks",": plusieurs hooks dans une seule méthode ",[361,514,380],{},"; ils partagent le même cache sous-jacent de façon transparente",[383,517],{},[348,519,521],{"id":520},"points-darchitecture","Points d'architecture",[353,523,524,525,527,528,530,531,420,534,420,537,540,541,373,544,547,548,550,551,420,554,556],{},"Le package est un adaptateur léger. Chaque hook appelle les mêmes méthodes ",[361,526,202],{}," que ",[361,529,108],{}," utilise ",[361,532,533],{},"watchQuery",[361,535,536],{},"watchState",[361,538,539],{},"watchFetchStatus"," via ",[361,542,543],{},"useEffect",[361,545,546],{},"useState",". Le cache est partagé : si un ",[361,549,108],{}," a déjà fetché ",[361,552,553],{},"['users', id]",[361,555,372],{}," l'obtient à la première frame depuis la même entrée.",[558,559,565],"pre",{"className":560,"code":562,"language":563,"meta":564},[561],"language-text","qora_hooks/\n└── lib/src/hooks/\n    ├── use_query.dart          ← useState(client.getQueryState) + useEffect(watchQuery.listen)\n    ├── use_mutation.dart       ← useRef(MutationController) + useState(MutationState)\n    ├── use_infinite_query.dart ← useState(InfiniteQueryState) + useEffect(observer.stream.listen)\n    ├── use_query_client.dart   ← QoraScope.of(context)\n    ├── use_is_fetching.dart    ← client.fetchingCountStream.listen\n    └── use_is_mutating.dart    ← client.mutationEvents + activeMutations\n","text","",[361,566,562],{"__ignoreMap":564},[353,568,569,570,573,574,577,578,373,581,584,585,587],{},"Les widgets doivent étendre ",[361,571,572],{},"HookWidget"," (ou ",[361,575,576],{},"HookConsumerWidget"," pour Riverpod). ",[361,579,580],{},"StatelessWidget",[361,582,583],{},"StatefulWidget"," standard ne sont pas supportés, utiliser ",[361,586,108],{}," à la place.",[383,589],{},[348,591,593],{"id":592},"détails-dimplémentation","Détails d'implémentation",[595,596,598,599],"h3",{"id":597},"composition-de-hooks-un-écran-complet-dans-un-seul-build","Composition de hooks : un écran complet dans un seul ",[361,600,380],{},[353,602,603,604,606,607,606,609,611,612,614,615,618],{},"Le pattern emblématique : ",[361,605,372],{}," + ",[361,608,376],{},[361,610,464],{}," dans la même méthode ",[361,613,380],{},", sans imbrication, sans ",[361,616,617],{},"State"," personnalisé :",[558,620,625],{"className":621,"code":622,"filename":623,"language":624,"meta":564,"style":564},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","class ProfileScreen extends HookWidget {\n  final String userId;\n  const ProfileScreen({super.key, required this.userId});\n\n  @override\n  Widget build(BuildContext context) {\n    // ── Données ──────────────────────────────────────────────────────────\n    final client   = useQueryClient();\n    final userQuery = useQuery\u003CUser>(\n      key: ['users', userId],\n      fetcher: () => Api.getUser(userId),\n      options: const QoraOptions(staleTime: Duration(minutes: 5)),\n    );\n    final updateMutation = useMutation\u003CUser, UpdateUserInput>(\n      mutator: Api.updateUser,\n      options: MutationOptions(\n        onSuccess: (user, _, __) async =>\n            client.invalidate(['users', userId]),\n      ),\n    );\n\n    // ── UI ───────────────────────────────────────────────────────────────\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Profil'),\n        actions: [\n          if (updateMutation.isError)\n            IconButton(\n              icon: const Icon(Icons.warning_amber, color: Colors.orange),\n              tooltip: 'Sauvegarde échouée : appuyer pour réessayer',\n              onPressed: updateMutation.reset,\n            ),\n        ],\n      ),\n      body: switch (userQuery) {\n        Initial() || Loading(previousData: null) =>\n            const Center(child: CircularProgressIndicator()),\n        Failure(:final error, previousData: null) => ErrorScreen(error),\n        _ => ProfileForm(\n            user:        userQuery.dataOrNull!,\n            isSaving:    updateMutation.isPending,\n            saveError:   updateMutation.error,\n            onSave: (input) => updateMutation.mutate(input),\n          ),\n      },\n    );\n  }\n}\n","lib/features/profile/ui/profile_screen.dart","dart",[361,626,627,650,666,699,706,712,731,738,758,780,804,831,867,875,899,916,929,957,979,987,994,999,1005,1016,1029,1051,1062,1076,1084,1124,1137,1154,1162,1170,1177,1191,1220,1242,1279,1292,1311,1328,1346,1370,1378,1386,1393,1399],{"__ignoreMap":564},[628,629,632,636,640,643,646],"span",{"class":630,"line":631},"line",1,[628,633,635],{"class":634},"sMK4o","class",[628,637,639],{"class":638},"sBMFI"," ProfileScreen",[628,641,642],{"class":634}," extends",[628,644,645],{"class":638}," HookWidget",[628,647,649],{"class":648},"sTEyZ"," {\n",[628,651,653,657,660,663],{"class":630,"line":652},2,[628,654,656],{"class":655},"spNyl","  final",[628,658,659],{"class":638}," String",[628,661,662],{"class":648}," userId",[628,664,665],{"class":634},";\n",[628,667,669,672,674,677,680,683,686,689,692,694,697],{"class":630,"line":668},3,[628,670,671],{"class":655},"  const",[628,673,639],{"class":638},[628,675,676],{"class":648},"({super",[628,678,679],{"class":634},".",[628,681,682],{"class":648},"key",[628,684,685],{"class":634},",",[628,687,688],{"class":655}," required",[628,690,691],{"class":648}," this",[628,693,679],{"class":634},[628,695,696],{"class":648},"userId})",[628,698,665],{"class":634},[628,700,702],{"class":630,"line":701},4,[628,703,705],{"emptyLinePlaceholder":704},true,"\n",[628,707,709],{"class":630,"line":708},5,[628,710,711],{"class":655},"  @override\n",[628,713,715,718,722,725,728],{"class":630,"line":714},6,[628,716,717],{"class":638},"  Widget",[628,719,721],{"class":720},"s2Zo4"," build",[628,723,724],{"class":648},"(",[628,726,727],{"class":638},"BuildContext",[628,729,730],{"class":648}," context) {\n",[628,732,734],{"class":630,"line":733},7,[628,735,737],{"class":736},"sHwdD","    // ── Données ──────────────────────────────────────────────────────────\n",[628,739,741,744,747,750,753,756],{"class":630,"line":740},8,[628,742,743],{"class":655},"    final",[628,745,746],{"class":648}," client   ",[628,748,749],{"class":634},"=",[628,751,752],{"class":720}," useQueryClient",[628,754,755],{"class":648},"()",[628,757,665],{"class":634},[628,759,761,763,766,768,771,774,777],{"class":630,"line":760},9,[628,762,743],{"class":655},[628,764,765],{"class":648}," userQuery ",[628,767,749],{"class":634},[628,769,770],{"class":720}," useQuery",[628,772,773],{"class":648},"\u003C",[628,775,776],{"class":638},"User",[628,778,779],{"class":648},">(\n",[628,781,783,786,789,792,796,798,801],{"class":630,"line":782},10,[628,784,785],{"class":648},"      key",[628,787,788],{"class":634},":",[628,790,791],{"class":648}," [",[628,793,795],{"class":794},"sfazB","'users'",[628,797,685],{"class":634},[628,799,800],{"class":648}," userId]",[628,802,803],{"class":634},",\n",[628,805,807,810,812,815,818,821,823,826,829],{"class":630,"line":806},11,[628,808,809],{"class":648},"      fetcher",[628,811,788],{"class":634},[628,813,814],{"class":648}," () ",[628,816,817],{"class":634},"=>",[628,819,820],{"class":638}," Api",[628,822,679],{"class":634},[628,824,825],{"class":720},"getUser",[628,827,828],{"class":648},"(userId)",[628,830,803],{"class":634},[628,832,834,837,839,842,845,848,850,853,856,858,862,865],{"class":630,"line":833},12,[628,835,836],{"class":648},"      options",[628,838,788],{"class":634},[628,840,841],{"class":655}," const",[628,843,844],{"class":638}," QoraOptions",[628,846,847],{"class":648},"(staleTime",[628,849,788],{"class":634},[628,851,852],{"class":638}," Duration",[628,854,855],{"class":648},"(minutes",[628,857,788],{"class":634},[628,859,861],{"class":860},"sbssI"," 5",[628,863,864],{"class":648},"))",[628,866,803],{"class":634},[628,868,870,873],{"class":630,"line":869},13,[628,871,872],{"class":648},"    )",[628,874,665],{"class":634},[628,876,878,880,883,885,888,890,892,894,897],{"class":630,"line":877},14,[628,879,743],{"class":655},[628,881,882],{"class":648}," updateMutation ",[628,884,749],{"class":634},[628,886,887],{"class":720}," useMutation",[628,889,773],{"class":648},[628,891,776],{"class":638},[628,893,420],{"class":648},[628,895,896],{"class":638},"UpdateUserInput",[628,898,779],{"class":648},[628,900,902,905,907,909,911,914],{"class":630,"line":901},15,[628,903,904],{"class":648},"      mutator",[628,906,788],{"class":634},[628,908,820],{"class":638},[628,910,679],{"class":634},[628,912,913],{"class":648},"updateUser",[628,915,803],{"class":634},[628,917,919,921,923,926],{"class":630,"line":918},16,[628,920,836],{"class":648},[628,922,788],{"class":634},[628,924,925],{"class":638}," MutationOptions",[628,927,928],{"class":648},"(\n",[628,930,932,935,937,940,942,945,947,950,954],{"class":630,"line":931},17,[628,933,934],{"class":648},"        onSuccess",[628,936,788],{"class":634},[628,938,939],{"class":648}," (user",[628,941,685],{"class":634},[628,943,944],{"class":648}," _",[628,946,685],{"class":634},[628,948,949],{"class":648}," __) ",[628,951,953],{"class":952},"s7zQu","async",[628,955,956],{"class":634}," =>\n",[628,958,960,963,965,967,970,972,974,977],{"class":630,"line":959},18,[628,961,962],{"class":648},"            client",[628,964,679],{"class":634},[628,966,471],{"class":720},[628,968,969],{"class":648},"([",[628,971,795],{"class":794},[628,973,685],{"class":634},[628,975,976],{"class":648}," userId])",[628,978,803],{"class":634},[628,980,982,985],{"class":630,"line":981},19,[628,983,984],{"class":648},"      )",[628,986,803],{"class":634},[628,988,990,992],{"class":630,"line":989},20,[628,991,872],{"class":648},[628,993,665],{"class":634},[628,995,997],{"class":630,"line":996},21,[628,998,705],{"emptyLinePlaceholder":704},[628,1000,1002],{"class":630,"line":1001},22,[628,1003,1004],{"class":736},"    // ── UI ───────────────────────────────────────────────────────────────\n",[628,1006,1008,1011,1014],{"class":630,"line":1007},23,[628,1009,1010],{"class":952},"    return",[628,1012,1013],{"class":638}," Scaffold",[628,1015,928],{"class":648},[628,1017,1019,1022,1024,1027],{"class":630,"line":1018},24,[628,1020,1021],{"class":648},"      appBar",[628,1023,788],{"class":634},[628,1025,1026],{"class":638}," AppBar",[628,1028,928],{"class":648},[628,1030,1032,1035,1037,1039,1042,1044,1047,1049],{"class":630,"line":1031},25,[628,1033,1034],{"class":648},"        title",[628,1036,788],{"class":634},[628,1038,841],{"class":655},[628,1040,1041],{"class":638}," Text",[628,1043,724],{"class":648},[628,1045,1046],{"class":794},"'Profil'",[628,1048,475],{"class":648},[628,1050,803],{"class":634},[628,1052,1054,1057,1059],{"class":630,"line":1053},26,[628,1055,1056],{"class":648},"        actions",[628,1058,788],{"class":634},[628,1060,1061],{"class":648}," [\n",[628,1063,1065,1068,1071,1073],{"class":630,"line":1064},27,[628,1066,1067],{"class":952},"          if",[628,1069,1070],{"class":648}," (updateMutation",[628,1072,679],{"class":634},[628,1074,1075],{"class":648},"isError)\n",[628,1077,1079,1082],{"class":630,"line":1078},28,[628,1080,1081],{"class":638},"            IconButton",[628,1083,928],{"class":648},[628,1085,1087,1090,1092,1094,1097,1099,1102,1104,1107,1109,1112,1114,1117,1119,1122],{"class":630,"line":1086},29,[628,1088,1089],{"class":648},"              icon",[628,1091,788],{"class":634},[628,1093,841],{"class":655},[628,1095,1096],{"class":638}," Icon",[628,1098,724],{"class":648},[628,1100,1101],{"class":638},"Icons",[628,1103,679],{"class":634},[628,1105,1106],{"class":648},"warning_amber",[628,1108,685],{"class":634},[628,1110,1111],{"class":648}," color",[628,1113,788],{"class":634},[628,1115,1116],{"class":638}," Colors",[628,1118,679],{"class":634},[628,1120,1121],{"class":648},"orange)",[628,1123,803],{"class":634},[628,1125,1127,1130,1132,1135],{"class":630,"line":1126},30,[628,1128,1129],{"class":648},"              tooltip",[628,1131,788],{"class":634},[628,1133,1134],{"class":794}," 'Sauvegarde échouée : appuyer pour réessayer'",[628,1136,803],{"class":634},[628,1138,1140,1143,1145,1148,1150,1152],{"class":630,"line":1139},31,[628,1141,1142],{"class":648},"              onPressed",[628,1144,788],{"class":634},[628,1146,1147],{"class":648}," updateMutation",[628,1149,679],{"class":634},[628,1151,435],{"class":648},[628,1153,803],{"class":634},[628,1155,1157,1160],{"class":630,"line":1156},32,[628,1158,1159],{"class":648},"            )",[628,1161,803],{"class":634},[628,1163,1165,1168],{"class":630,"line":1164},33,[628,1166,1167],{"class":648},"        ]",[628,1169,803],{"class":634},[628,1171,1173,1175],{"class":630,"line":1172},34,[628,1174,984],{"class":648},[628,1176,803],{"class":634},[628,1178,1180,1183,1185,1188],{"class":630,"line":1179},35,[628,1181,1182],{"class":648},"      body",[628,1184,788],{"class":634},[628,1186,1187],{"class":952}," switch",[628,1189,1190],{"class":648}," (userQuery) {\n",[628,1192,1194,1197,1200,1203,1206,1209,1211,1214,1217],{"class":630,"line":1193},36,[628,1195,1196],{"class":638},"        Initial",[628,1198,1199],{"class":648},"() ",[628,1201,1202],{"class":634},"||",[628,1204,1205],{"class":638}," Loading",[628,1207,1208],{"class":648},"(previousData",[628,1210,788],{"class":634},[628,1212,1213],{"class":634}," null",[628,1215,1216],{"class":648},") ",[628,1218,1219],{"class":634},"=>\n",[628,1221,1223,1226,1229,1232,1234,1237,1240],{"class":630,"line":1222},37,[628,1224,1225],{"class":655},"            const",[628,1227,1228],{"class":638}," Center",[628,1230,1231],{"class":648},"(child",[628,1233,788],{"class":634},[628,1235,1236],{"class":638}," CircularProgressIndicator",[628,1238,1239],{"class":648},"())",[628,1241,803],{"class":634},[628,1243,1245,1248,1250,1252,1255,1258,1260,1263,1265,1267,1269,1271,1274,1277],{"class":630,"line":1244},38,[628,1246,1247],{"class":638},"        Failure",[628,1249,724],{"class":648},[628,1251,788],{"class":634},[628,1253,1254],{"class":655},"final",[628,1256,1257],{"class":648}," error",[628,1259,685],{"class":634},[628,1261,1262],{"class":648}," previousData",[628,1264,788],{"class":634},[628,1266,1213],{"class":634},[628,1268,1216],{"class":648},[628,1270,817],{"class":634},[628,1272,1273],{"class":638}," ErrorScreen",[628,1275,1276],{"class":648},"(error)",[628,1278,803],{"class":634},[628,1280,1282,1285,1287,1290],{"class":630,"line":1281},39,[628,1283,1284],{"class":648},"        _ ",[628,1286,817],{"class":634},[628,1288,1289],{"class":638}," ProfileForm",[628,1291,928],{"class":648},[628,1293,1295,1298,1300,1303,1305,1308],{"class":630,"line":1294},40,[628,1296,1297],{"class":648},"            user",[628,1299,788],{"class":634},[628,1301,1302],{"class":648},"        userQuery",[628,1304,679],{"class":634},[628,1306,1307],{"class":648},"dataOrNull",[628,1309,1310],{"class":634},"!,\n",[628,1312,1314,1317,1319,1322,1324,1326],{"class":630,"line":1313},41,[628,1315,1316],{"class":648},"            isSaving",[628,1318,788],{"class":634},[628,1320,1321],{"class":648},"    updateMutation",[628,1323,679],{"class":634},[628,1325,426],{"class":648},[628,1327,803],{"class":634},[628,1329,1331,1334,1336,1339,1341,1344],{"class":630,"line":1330},42,[628,1332,1333],{"class":648},"            saveError",[628,1335,788],{"class":634},[628,1337,1338],{"class":648},"   updateMutation",[628,1340,679],{"class":634},[628,1342,1343],{"class":648},"error",[628,1345,803],{"class":634},[628,1347,1349,1352,1354,1357,1359,1361,1363,1365,1368],{"class":630,"line":1348},43,[628,1350,1351],{"class":648},"            onSave",[628,1353,788],{"class":634},[628,1355,1356],{"class":648}," (input) ",[628,1358,817],{"class":634},[628,1360,1147],{"class":648},[628,1362,679],{"class":634},[628,1364,419],{"class":720},[628,1366,1367],{"class":648},"(input)",[628,1369,803],{"class":634},[628,1371,1373,1376],{"class":630,"line":1372},44,[628,1374,1375],{"class":648},"          )",[628,1377,803],{"class":634},[628,1379,1381,1384],{"class":630,"line":1380},45,[628,1382,1383],{"class":648},"      }",[628,1385,803],{"class":634},[628,1387,1389,1391],{"class":630,"line":1388},46,[628,1390,872],{"class":648},[628,1392,665],{"class":634},[628,1394,1396],{"class":630,"line":1395},47,[628,1397,1398],{"class":648},"  }\n",[628,1400,1402],{"class":630,"line":1401},48,[628,1403,1404],{"class":648},"}\n",[353,1406,1407,1408,606,1410,1412,1413,1416],{},"L'équivalent avec ",[361,1409,108],{},[361,1411,113],{}," nécessiterait deux callbacks de builder imbriqués et un ",[361,1414,1415],{},"Stack"," pour superposer l'état de sauvegarde, environ 2× le nombre de lignes pour la même logique.",[595,1418,1420,1422],{"id":1419},"usequery-est-synchrone-sur-un-hit-de-cache",[361,1421,372],{}," est synchrone sur un hit de cache",[353,1424,1425,1426,1429],{},"Le détail d'implémentation clé dans ",[361,1427,1428],{},"use_query.dart"," :",[558,1431,1433],{"className":621,"code":1432,"language":624,"meta":564,"style":564},"// Initialiser depuis le cache : évite un flash de chargement quand les données sont déjà fraîches.\nfinal state = useState\u003CQoraState\u003CT>>(client.getQueryState\u003CT>(key));\n",[361,1434,1435,1440],{"__ignoreMap":564},[628,1436,1437],{"class":630,"line":631},[628,1438,1439],{"class":736},"// Initialiser depuis le cache : évite un flash de chargement quand les données sont déjà fraîches.\n",[628,1441,1442,1444,1447,1449,1452,1454,1456,1458,1461,1464,1466,1469,1471,1473,1476],{"class":630,"line":652},[628,1443,1254],{"class":655},[628,1445,1446],{"class":648}," state ",[628,1448,749],{"class":634},[628,1450,1451],{"class":720}," useState",[628,1453,773],{"class":648},[628,1455,211],{"class":638},[628,1457,773],{"class":648},[628,1459,1460],{"class":638},"T",[628,1462,1463],{"class":648},">>(client",[628,1465,679],{"class":634},[628,1467,1468],{"class":720},"getQueryState",[628,1470,773],{"class":648},[628,1472,1460],{"class":638},[628,1474,1475],{"class":648},">(key))",[628,1477,665],{"class":634},[353,1479,1480,1482,1483,1486,1487,416,1490,420,1493,1495,1496,1499,1500,1503,1504,1507,1508,1511,1512,530,1514,1516],{},[361,1481,1468],{}," est une lecture ",[356,1484,1485],{},"synchrone"," de l'entrée de cache courante. Si un autre widget a déjà fetché ",[361,1488,1489],{},"['users', userId]",[361,1491,1492],{},"staleTime: 5 minutes",[361,1494,372],{}," retourne ",[361,1497,1498],{},"Success(data: user)"," à la ",[356,1501,1502],{},"première frame"," : aucun flash ",[361,1505,1506],{},"Initial",", aucun état ",[361,1509,1510],{},"Loading",". C'est identique à la façon dont ",[361,1513,108],{},[361,1515,536],{}," (qui lit aussi la valeur courante de façon synchrone avant le démarrage du stream).",[595,1518,1520,1522],{"id":1519},"useisfetching-barre-de-progression-globale-sans-couplage",[361,1521,482],{}," : barre de progression globale sans couplage",[353,1524,1525,1526,1528,1529,1533],{},"Un besoin UX courant : afficher un ",[361,1527,493],{}," fin en haut de l'app dès qu'",[1530,1531,1532],"em",{},"une"," requête est en chargement. Avec les hooks, c'est une ligne dans n'importe quel widget, sans connaissance des requêtes spécifiques :",[558,1535,1538],{"className":621,"code":1536,"filename":1537,"language":624,"meta":564,"style":564},"class AppProgressBar extends HookWidget {\n  const AppProgressBar({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    final isFetching = useIsFetching(); // true si UNE QUELCONQUE requête a une demande en vol\n\n    return AnimatedOpacity(\n      opacity: isFetching ? 1.0 : 0.0,\n      duration: const Duration(milliseconds: 250),\n      child: const LinearProgressIndicator(minHeight: 2),\n    );\n  }\n}\n","lib/shared/widgets/app_progress_bar.dart",[361,1539,1540,1553,1568,1572,1576,1588,1608,1612,1621,1643,1666,1690,1696,1700],{"__ignoreMap":564},[628,1541,1542,1544,1547,1549,1551],{"class":630,"line":631},[628,1543,635],{"class":634},[628,1545,1546],{"class":638}," AppProgressBar",[628,1548,642],{"class":634},[628,1550,645],{"class":638},[628,1552,649],{"class":648},[628,1554,1555,1557,1559,1561,1563,1566],{"class":630,"line":652},[628,1556,671],{"class":655},[628,1558,1546],{"class":638},[628,1560,676],{"class":648},[628,1562,679],{"class":634},[628,1564,1565],{"class":648},"key})",[628,1567,665],{"class":634},[628,1569,1570],{"class":630,"line":668},[628,1571,705],{"emptyLinePlaceholder":704},[628,1573,1574],{"class":630,"line":701},[628,1575,711],{"class":655},[628,1577,1578,1580,1582,1584,1586],{"class":630,"line":708},[628,1579,717],{"class":638},[628,1581,721],{"class":720},[628,1583,724],{"class":648},[628,1585,727],{"class":638},[628,1587,730],{"class":648},[628,1589,1590,1592,1595,1597,1600,1602,1605],{"class":630,"line":714},[628,1591,743],{"class":655},[628,1593,1594],{"class":648}," isFetching ",[628,1596,749],{"class":634},[628,1598,1599],{"class":720}," useIsFetching",[628,1601,755],{"class":648},[628,1603,1604],{"class":634},";",[628,1606,1607],{"class":736}," // true si UNE QUELCONQUE requête a une demande en vol\n",[628,1609,1610],{"class":630,"line":733},[628,1611,705],{"emptyLinePlaceholder":704},[628,1613,1614,1616,1619],{"class":630,"line":740},[628,1615,1010],{"class":952},[628,1617,1618],{"class":638}," AnimatedOpacity",[628,1620,928],{"class":648},[628,1622,1623,1626,1628,1630,1633,1636,1638,1641],{"class":630,"line":760},[628,1624,1625],{"class":648},"      opacity",[628,1627,788],{"class":634},[628,1629,1594],{"class":648},[628,1631,1632],{"class":634},"?",[628,1634,1635],{"class":860}," 1.0",[628,1637,1429],{"class":634},[628,1639,1640],{"class":860}," 0.0",[628,1642,803],{"class":634},[628,1644,1645,1648,1650,1652,1654,1657,1659,1662,1664],{"class":630,"line":782},[628,1646,1647],{"class":648},"      duration",[628,1649,788],{"class":634},[628,1651,841],{"class":655},[628,1653,852],{"class":638},[628,1655,1656],{"class":648},"(milliseconds",[628,1658,788],{"class":634},[628,1660,1661],{"class":860}," 250",[628,1663,475],{"class":648},[628,1665,803],{"class":634},[628,1667,1668,1671,1673,1675,1678,1681,1683,1686,1688],{"class":630,"line":806},[628,1669,1670],{"class":648},"      child",[628,1672,788],{"class":634},[628,1674,841],{"class":655},[628,1676,1677],{"class":638}," LinearProgressIndicator",[628,1679,1680],{"class":648},"(minHeight",[628,1682,788],{"class":634},[628,1684,1685],{"class":860}," 2",[628,1687,475],{"class":648},[628,1689,803],{"class":634},[628,1691,1692,1694],{"class":630,"line":833},[628,1693,872],{"class":648},[628,1695,665],{"class":634},[628,1697,1698],{"class":630,"line":869},[628,1699,1398],{"class":648},[628,1701,1702],{"class":630,"line":877},[628,1703,1404],{"class":648},[353,1705,1706,1708,1709,1712,1713,1715,1716,1719,1720,1723],{},[361,1707,482],{}," ne rebuilde que quand la valeur ",[356,1710,1711],{},"franchit zéro",", pas à chaque changement de compteur. Si 5 requêtes s'exécutent et qu'une se termine, le widget ne rebuilde pas (toujours ",[361,1714,489],{},"). Il rebuilde uniquement quand la dernière requête se termine (",[361,1717,1718],{},"true → false",") ou quand la première commence (",[361,1721,1722],{},"false → true",").",[595,1725,1727,1730],{"id":1726},"useinfinitequery-défilement-infini-sans-observer",[361,1728,1729],{},"useInfiniteQuery"," : défilement infini sans observer",[353,1732,1733,1734,1737,1738,1740],{},"L'API hooks encapsule ",[361,1735,1736],{},"InfiniteQueryObserver"," dans un ",[361,1739,445],{}," avec une interface plate :",[558,1742,1745],{"className":621,"code":1743,"filename":1744,"language":624,"meta":564,"style":564},"class PostsScreen extends HookWidget {\n  @override\n  Widget build(BuildContext context) {\n    final query = useInfiniteQuery\u003CPostsPage, String?>(\n      key: const ['posts'],\n      fetcher: (cursor) => Api.getPosts(cursor: cursor),\n      getNextPageParam: (page) => page.nextCursor,\n      initialPageParam: null,\n    );\n\n    if (query.isLoading) return const Center(child: CircularProgressIndicator());\n    if (query.error != null && query.pages.isEmpty) return ErrorScreen(query.error!);\n\n    final posts = query.pages.expand((p) => p.posts).toList();\n\n    return ListView.builder(\n      itemCount: posts.length + (query.hasNextPage ? 1 : 0),\n      itemBuilder: (context, i) {\n        if (i == posts.length) {\n          // Déclencher automatiquement la page suivante quand l'élément sentinelle est construit\n          if (!query.isFetchingNextPage) query.fetchNextPage();\n          return const Center(child: CircularProgressIndicator());\n        }\n        return PostTile(posts[i]);\n      },\n    );\n  }\n}\n","lib/features/posts/ui/posts_screen.dart",[361,1746,1747,1760,1764,1776,1801,1819,1847,1869,1879,1885,1889,1919,1968,1972,2014,2018,2032,2071,2086,2104,2109,2134,2153,2158,2171,2177,2183,2187],{"__ignoreMap":564},[628,1748,1749,1751,1754,1756,1758],{"class":630,"line":631},[628,1750,635],{"class":634},[628,1752,1753],{"class":638}," PostsScreen",[628,1755,642],{"class":634},[628,1757,645],{"class":638},[628,1759,649],{"class":648},[628,1761,1762],{"class":630,"line":652},[628,1763,711],{"class":655},[628,1765,1766,1768,1770,1772,1774],{"class":630,"line":668},[628,1767,717],{"class":638},[628,1769,721],{"class":720},[628,1771,724],{"class":648},[628,1773,727],{"class":638},[628,1775,730],{"class":648},[628,1777,1778,1780,1783,1785,1788,1790,1793,1795,1798],{"class":630,"line":701},[628,1779,743],{"class":655},[628,1781,1782],{"class":648}," query ",[628,1784,749],{"class":634},[628,1786,1787],{"class":720}," useInfiniteQuery",[628,1789,773],{"class":648},[628,1791,1792],{"class":638},"PostsPage",[628,1794,420],{"class":648},[628,1796,1797],{"class":638},"String",[628,1799,1800],{"class":648},"?>(\n",[628,1802,1803,1805,1807,1809,1811,1814,1817],{"class":630,"line":708},[628,1804,785],{"class":648},[628,1806,788],{"class":634},[628,1808,841],{"class":655},[628,1810,791],{"class":648},[628,1812,1813],{"class":794},"'posts'",[628,1815,1816],{"class":648},"]",[628,1818,803],{"class":634},[628,1820,1821,1823,1825,1828,1830,1832,1834,1837,1840,1842,1845],{"class":630,"line":714},[628,1822,809],{"class":648},[628,1824,788],{"class":634},[628,1826,1827],{"class":648}," (cursor) ",[628,1829,817],{"class":634},[628,1831,820],{"class":638},[628,1833,679],{"class":634},[628,1835,1836],{"class":720},"getPosts",[628,1838,1839],{"class":648},"(cursor",[628,1841,788],{"class":634},[628,1843,1844],{"class":648}," cursor)",[628,1846,803],{"class":634},[628,1848,1849,1852,1854,1857,1859,1862,1864,1867],{"class":630,"line":733},[628,1850,1851],{"class":648},"      getNextPageParam",[628,1853,788],{"class":634},[628,1855,1856],{"class":648}," (page) ",[628,1858,817],{"class":634},[628,1860,1861],{"class":648}," page",[628,1863,679],{"class":634},[628,1865,1866],{"class":648},"nextCursor",[628,1868,803],{"class":634},[628,1870,1871,1874,1876],{"class":630,"line":740},[628,1872,1873],{"class":648},"      initialPageParam",[628,1875,788],{"class":634},[628,1877,1878],{"class":634}," null,\n",[628,1880,1881,1883],{"class":630,"line":760},[628,1882,872],{"class":648},[628,1884,665],{"class":634},[628,1886,1887],{"class":630,"line":782},[628,1888,705],{"emptyLinePlaceholder":704},[628,1890,1891,1894,1897,1899,1902,1905,1907,1909,1911,1913,1915,1917],{"class":630,"line":806},[628,1892,1893],{"class":952},"    if",[628,1895,1896],{"class":648}," (query",[628,1898,679],{"class":634},[628,1900,1901],{"class":648},"isLoading) ",[628,1903,1904],{"class":952},"return",[628,1906,841],{"class":655},[628,1908,1228],{"class":638},[628,1910,1231],{"class":648},[628,1912,788],{"class":634},[628,1914,1236],{"class":638},[628,1916,1239],{"class":648},[628,1918,665],{"class":634},[628,1920,1921,1923,1925,1927,1930,1933,1935,1938,1941,1943,1945,1947,1950,1952,1954,1957,1959,1961,1964,1966],{"class":630,"line":833},[628,1922,1893],{"class":952},[628,1924,1896],{"class":648},[628,1926,679],{"class":634},[628,1928,1929],{"class":648},"error ",[628,1931,1932],{"class":634},"!=",[628,1934,1213],{"class":634},[628,1936,1937],{"class":634}," &&",[628,1939,1940],{"class":648}," query",[628,1942,679],{"class":634},[628,1944,448],{"class":648},[628,1946,679],{"class":634},[628,1948,1949],{"class":648},"isEmpty) ",[628,1951,1904],{"class":952},[628,1953,1273],{"class":638},[628,1955,1956],{"class":648},"(query",[628,1958,679],{"class":634},[628,1960,1343],{"class":648},[628,1962,1963],{"class":634},"!",[628,1965,475],{"class":648},[628,1967,665],{"class":634},[628,1969,1970],{"class":630,"line":869},[628,1971,705],{"emptyLinePlaceholder":704},[628,1973,1974,1976,1979,1981,1983,1985,1987,1989,1992,1995,1997,2000,2002,2005,2007,2010,2012],{"class":630,"line":877},[628,1975,743],{"class":655},[628,1977,1978],{"class":648}," posts ",[628,1980,749],{"class":634},[628,1982,1940],{"class":648},[628,1984,679],{"class":634},[628,1986,448],{"class":648},[628,1988,679],{"class":634},[628,1990,1991],{"class":720},"expand",[628,1993,1994],{"class":648},"((p) ",[628,1996,817],{"class":634},[628,1998,1999],{"class":648}," p",[628,2001,679],{"class":634},[628,2003,2004],{"class":648},"posts)",[628,2006,679],{"class":634},[628,2008,2009],{"class":720},"toList",[628,2011,755],{"class":648},[628,2013,665],{"class":634},[628,2015,2016],{"class":630,"line":901},[628,2017,705],{"emptyLinePlaceholder":704},[628,2019,2020,2022,2025,2027,2030],{"class":630,"line":918},[628,2021,1010],{"class":952},[628,2023,2024],{"class":638}," ListView",[628,2026,679],{"class":634},[628,2028,2029],{"class":720},"builder",[628,2031,928],{"class":648},[628,2033,2034,2037,2039,2042,2044,2047,2050,2052,2054,2057,2059,2062,2064,2067,2069],{"class":630,"line":931},[628,2035,2036],{"class":648},"      itemCount",[628,2038,788],{"class":634},[628,2040,2041],{"class":648}," posts",[628,2043,679],{"class":634},[628,2045,2046],{"class":648},"length ",[628,2048,2049],{"class":634},"+",[628,2051,1896],{"class":648},[628,2053,679],{"class":634},[628,2055,2056],{"class":648},"hasNextPage ",[628,2058,1632],{"class":634},[628,2060,2061],{"class":860}," 1",[628,2063,1429],{"class":634},[628,2065,2066],{"class":860}," 0",[628,2068,475],{"class":648},[628,2070,803],{"class":634},[628,2072,2073,2076,2078,2081,2083],{"class":630,"line":959},[628,2074,2075],{"class":648},"      itemBuilder",[628,2077,788],{"class":634},[628,2079,2080],{"class":648}," (context",[628,2082,685],{"class":634},[628,2084,2085],{"class":648}," i) {\n",[628,2087,2088,2091,2094,2097,2099,2101],{"class":630,"line":981},[628,2089,2090],{"class":952},"        if",[628,2092,2093],{"class":648}," (i ",[628,2095,2096],{"class":634},"==",[628,2098,2041],{"class":648},[628,2100,679],{"class":634},[628,2102,2103],{"class":648},"length) {\n",[628,2105,2106],{"class":630,"line":989},[628,2107,2108],{"class":736},"          // Déclencher automatiquement la page suivante quand l'élément sentinelle est construit\n",[628,2110,2111,2113,2116,2118,2121,2123,2126,2128,2130,2132],{"class":630,"line":996},[628,2112,1067],{"class":952},[628,2114,2115],{"class":648}," (",[628,2117,1963],{"class":634},[628,2119,2120],{"class":648},"query",[628,2122,679],{"class":634},[628,2124,2125],{"class":648},"isFetchingNextPage) query",[628,2127,679],{"class":634},[628,2129,451],{"class":720},[628,2131,755],{"class":648},[628,2133,665],{"class":634},[628,2135,2136,2139,2141,2143,2145,2147,2149,2151],{"class":630,"line":1001},[628,2137,2138],{"class":952},"          return",[628,2140,841],{"class":655},[628,2142,1228],{"class":638},[628,2144,1231],{"class":648},[628,2146,788],{"class":634},[628,2148,1236],{"class":638},[628,2150,1239],{"class":648},[628,2152,665],{"class":634},[628,2154,2155],{"class":630,"line":1007},[628,2156,2157],{"class":648},"        }\n",[628,2159,2160,2163,2166,2169],{"class":630,"line":1018},[628,2161,2162],{"class":952},"        return",[628,2164,2165],{"class":638}," PostTile",[628,2167,2168],{"class":648},"(posts[i])",[628,2170,665],{"class":634},[628,2172,2173,2175],{"class":630,"line":1031},[628,2174,1383],{"class":648},[628,2176,803],{"class":634},[628,2178,2179,2181],{"class":630,"line":1053},[628,2180,872],{"class":648},[628,2182,665],{"class":634},[628,2184,2185],{"class":630,"line":1064},[628,2186,1398],{"class":648},[628,2188,2189],{"class":630,"line":1078},[628,2190,1404],{"class":648},[353,2192,2193,2194,2197],{},"Aucun ",[361,2195,2196],{},"dispose"," explicite n'est requis: l'observer est lié au cycle de vie du hook et nettoyé automatiquement quand le widget est démonté.",[383,2199],{},[348,2201,2203],{"id":2202},"code-source","Code source",[558,2205,2208],{"className":2206,"code":2207,"language":563,"meta":564},[561],"examples/ex_06_hooks_integration/\n├── lib/\n│   ├── main.dart                          ← configuration QoraClient + QoraScope\n│   ├── shared/\n│   │   ├── api/json_placeholder_api.dart  ← client JSONPlaceholder partagé\n│   │   └── widgets/\n│   │       └── app_progress_bar.dart      ← indicateur global useIsFetching\n│   └── features/\n│       ├── profile/\n│       │   ├── models/user.dart           ← modèle User\n│       │   └── ui/profile_screen.dart     ← composition useQuery + useMutation\n│       └── posts/\n│           ├── models/posts_page.dart     ← modèle PostsPage\n│           └── ui/posts_screen.dart       ← useInfiniteQuery\n└── pubspec.yaml\n",[361,2209,2207],{"__ignoreMap":564},[353,2211,2212],{},[2213,2214,2218],"a",{"href":2215,"rel":2216},"https://github.com/meragix/qora/tree/main/examples/ex_06_hooks_integration",[2217],"nofollow","Voir le code source complet",[383,2220],{},[348,2222,2224],{"id":2223},"quand-utiliser-les-hooks-vs-les-builders","Quand utiliser les hooks vs les builders",[2226,2227,2228,2241],"table",{},[2229,2230,2231],"thead",{},[2232,2233,2234,2238],"tr",{},[2235,2236,2237],"th",{},"Situation",[2235,2239,2240],{},"Préférer",[2242,2243,2244,2255,2267,2280,2293],"tbody",{},[2232,2245,2246,2250],{},[2247,2248,2249],"td",{},"Requête unique, écran simple",[2247,2251,2252,2254],{},[361,2253,108],{}," ou hooks",[2232,2256,2257,2260],{},[2247,2258,2259],{},"Requête + mutation sur le même écran",[2247,2261,2262,606,2264,2266],{},[361,2263,372],{},[361,2265,376],{}," : élimine l'imbrication",[2232,2268,2269,2272],{},[2247,2270,2271],{},"Indicateur de chargement/mutation global",[2247,2273,2274,2276,2277,2279],{},[361,2275,482],{}," / ",[361,2278,501],{}," : impossible à faire proprement avec les builders",[2232,2281,2282,2288],{},[2247,2283,2284,2285],{},"Projet utilisant déjà ",[361,2286,2287],{},"flutter_hooks",[2247,2289,2290,2292],{},[361,2291,368],{}," : style cohérent dans la base de code",[2232,2294,2295,2302],{},[2247,2296,2297,2298,2276,2300],{},"Base de code ",[361,2299,580],{},[361,2301,583],{},[2247,2303,2304,2276,2306,2308,2309],{},[361,2305,108],{},[361,2307,113],{}," : les hooks requièrent ",[361,2310,572],{},[383,2312],{},[348,2314,2316],{"id":2315},"voir-aussi","Voir aussi",[390,2318,2319,2326,2334,2345],{},[393,2320,2321,2325],{},[2213,2322,2324],{"href":2323},"../flutter-integration/hooks","Référence des hooks",": API complète de tous les hooks",[393,2327,2328,2331,2332],{},[2213,2329,108],{"href":2330},"../flutter-integration/qora-builder",": alternative widget à ",[361,2333,372],{},[393,2335,2336,2340,2341,373,2343],{},[2213,2337,2339],{"href":2338},"../recipes/mutations","Recette de mutations",": patterns ",[361,2342,376],{},[361,2344,113],{},[393,2346,2347,359,2351,2353],{},[2213,2348,2350],{"href":2349},"./infinite-scroll","Étude de cas défilement infini",[361,2352,1729],{}," dans un feed de production",[2355,2356,2357],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":564,"searchDepth":652,"depth":652,"links":2359},[2360,2361,2362,2363,2373,2374,2375],{"id":350,"depth":652,"text":351},{"id":387,"depth":652,"text":388},{"id":520,"depth":652,"text":521},{"id":592,"depth":652,"text":593,"children":2364},[2365,2367,2369,2371],{"id":597,"depth":668,"text":2366},"Composition de hooks : un écran complet dans un seul build()",{"id":1419,"depth":668,"text":2368},"useQuery est synchrone sur un hit de cache",{"id":1519,"depth":668,"text":2370},"useIsFetching : barre de progression globale sans couplage",{"id":1726,"depth":668,"text":2372},"useInfiniteQuery : défilement infini sans observer",{"id":2202,"depth":652,"text":2203},{"id":2223,"depth":652,"text":2224},{"id":2315,"depth":652,"text":2316},"Remplacer l'imbrication des builders QoraBuilder par des appels de hooks plats et composables : useQuery, useMutation, useInfiniteQuery et indicateurs de fetch globaux dans un HookWidget.","md",null,{},{"icon":126},{"title":2382,"description":2383},"Étude de cas: Intégration des hooks - Qora","Utiliser qora_hooks avec flutter_hooks pour écrire des écrans d'état serveur sans StatefulWidget ni StreamSubscription. useQuery, useMutation, useIsFetching et composition de hooks.","zcGnurhTNmUNmCoruO30v8qFsrijs1itPpSIN3HrGF4",[2386,2388],{"title":315,"path":316,"stem":317,"description":2387,"icon":161,"children":-1},"Les requêtes se mettent automatiquement en pause hors ligne, les mutations se mettent en file pour plus tard, et tout rejoue à la reconnexion : avec prévention du thundering-herd intégrée.",{"title":323,"path":324,"stem":325,"description":2389,"icon":326,"children":-1},"Une app Flutter de niveau production combinant toutes les capacités Qora : PersistQoraClient, défilement infini avec pagination, create/toggle/delete optimistes, file de mutations hors ligne et bascule de connectivité simulée.",1794040411556]