[{"data":1,"prerenderedAt":4488},["ShallowReactive",2],{"blog:\u002Fblog\u002Fnuxt\u002Fpinia-colada-async-state":3},{"id":4,"title":5,"author":6,"body":7,"category":4472,"date":4473,"description":4474,"draft":4475,"extension":4476,"image":4477,"meta":4478,"navigation":431,"path":4479,"seo":4480,"series":4481,"seriesOrder":531,"seriesTitle":4482,"stem":4483,"tags":4484,"updatedAt":4477,"__hash__":4487},"blog\u002Fblog\u002Fnuxt\u002Fpinia-colada-async-state\u002Findex.md","Pinia Colada 非同步狀態管理","charles",{"type":8,"value":9,"toc":4421},"minimark",[10,14,18,34,37,40,44,49,138,142,198,200,203,206,232,236,322,324,327,335,339,382,384,388,391,579,582,674,677,913,916,1280,1283,1517,1519,1523,1526,1747,1750,1782,1785,2231,2233,2235,2238,2241,2792,2795,2801,2803,2806,2810,2921,2963,2966,3254,3256,3259,3262,3393,3396,3483,3485,3489,3493,3682,3686,3853,3856,3881,3883,3886,3890,3897,3989,3995,4020,4024,4029,4116,4121,4227,4230,4235,4240,4242,4245,4248,4322,4324,4327,4380,4382,4385,4417],[11,12,13],"h2",{"id":13},"這篇要解決什麼問題",[15,16,17],"p",{},"非同步狀態管理是前端開發的核心挑戰。傳統做法需要手動處理：",[19,20,21,25,28,31],"ul",{},[22,23,24],"li",{},"Loading 狀態追蹤",[22,26,27],{},"錯誤處理與重試",[22,29,30],{},"快取與資料同步",[22,32,33],{},"重複請求防止",[15,35,36],{},"這篇文章將說明如何用 Pinia Colada 優雅解決這些問題。",[38,39],"hr",{},[11,41,43],{"id":42},"為什麼選擇-pinia-colada","為什麼選擇 Pinia Colada",[45,46,48],"h3",{"id":47},"vs-tanstack-query","vs TanStack Query",[50,51,52,68],"table",{},[53,54,55],"thead",{},[56,57,58,62,65],"tr",{},[59,60,61],"th",{},"特性",[59,63,64],{},"Pinia Colada",[59,66,67],{},"TanStack Query",[69,70,71,83,94,105,116,127],"tbody",{},[56,72,73,77,80],{},[74,75,76],"td",{},"Vue 整合",[74,78,79],{},"原生支援",[74,81,82],{},"需要 adapter",[56,84,85,88,91],{},[74,86,87],{},"Pinia 整合",[74,89,90],{},"無縫整合",[74,92,93],{},"獨立運作",[56,95,96,99,102],{},[74,97,98],{},"學習曲線",[74,100,101],{},"較低",[74,103,104],{},"較高",[56,106,107,110,113],{},[74,108,109],{},"生態系",[74,111,112],{},"較新",[74,114,115],{},"成熟",[56,117,118,121,124],{},[74,119,120],{},"DevTools",[74,122,123],{},"Vue DevTools 原生支援",[74,125,126],{},"需要獨立擴充",[56,128,129,132,135],{},[74,130,131],{},"Bundle Size",[74,133,134],{},"較小",[74,136,137],{},"較大",[45,139,141],{"id":140},"vs-純-pinia","vs 純 Pinia",[50,143,144,155],{},[53,145,146],{},[56,147,148,150,152],{},[59,149,61],{},[59,151,64],{},[59,153,154],{},"純 Pinia",[69,156,157,168,179,189],{},[56,158,159,162,165],{},[74,160,161],{},"快取管理",[74,163,164],{},"內建",[74,166,167],{},"需手動實作",[56,169,170,173,176],{},[74,171,172],{},"Loading\u002FError 狀態",[74,174,175],{},"自動追蹤",[74,177,178],{},"需手動管理",[56,180,181,184,187],{},[74,182,183],{},"自動重新查詢",[74,185,186],{},"內建支援",[74,188,167],{},[56,190,191,194,196],{},[74,192,193],{},"樂觀更新",[74,195,186],{},[74,197,167],{},[38,199],{},[11,201,202],{"id":202},"安裝與設定",[45,204,205],{"id":205},"安裝套件",[207,208,213],"pre",{"className":209,"code":210,"language":211,"meta":212,"style":212},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","pnpm add @pinia\u002Fcolada\n","bash","",[214,215,216],"code",{"__ignoreMap":212},[217,218,221,225,229],"span",{"class":219,"line":220},"line",1,[217,222,224],{"class":223},"sbgvK","pnpm",[217,226,228],{"class":227},"s_sjI"," add",[217,230,231],{"class":227}," @pinia\u002Fcolada\n",[45,233,235],{"id":234},"nuxt-設定","Nuxt 設定",[207,237,241],{"className":238,"code":239,"language":240,"meta":212,"style":212},"language-typescript shiki shiki-themes material-theme-lighter github-light github-dark","\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: [\"@pinia\u002Fnuxt\", \"@pinia\u002Fcolada-nuxt\"],\n});\n","typescript",[214,242,243,249,271,310],{"__ignoreMap":212},[217,244,245],{"class":219,"line":220},[217,246,248],{"class":247},"sutJx","\u002F\u002F nuxt.config.ts\n",[217,250,252,256,259,263,267],{"class":219,"line":251},2,[217,253,255],{"class":254},"sVHd0","export",[217,257,258],{"class":254}," default",[217,260,262],{"class":261},"sGLFI"," defineNuxtConfig",[217,264,266],{"class":265},"su5hD","(",[217,268,270],{"class":269},"sP7_E","{\n",[217,272,274,278,281,284,288,291,293,296,299,302,304,307],{"class":219,"line":273},3,[217,275,277],{"class":276},"skxfh","  modules",[217,279,280],{"class":269},":",[217,282,283],{"class":265}," [",[217,285,287],{"class":286},"sjJ54","\"",[217,289,290],{"class":227},"@pinia\u002Fnuxt",[217,292,287],{"class":286},[217,294,295],{"class":269},",",[217,297,298],{"class":286}," \"",[217,300,301],{"class":227},"@pinia\u002Fcolada-nuxt",[217,303,287],{"class":286},[217,305,306],{"class":265},"]",[217,308,309],{"class":269},",\n",[217,311,313,316,319],{"class":219,"line":312},4,[217,314,315],{"class":269},"}",[217,317,318],{"class":265},")",[217,320,321],{"class":269},";\n",[38,323],{},[11,325,326],{"id":326},"目錄結構",[207,328,333],{"className":329,"code":331,"language":332},[330],"language-text","app\u002F\n├── queries\u002F              # Pinia Colada 查詢\n│   ├── users.ts         # 使用者相關查詢\n│   ├── resources.ts     # 資源相關查詢\n│   └── options.ts       # 下拉選單選項查詢\n├── stores\u002F               # Pinia Stores（非同步狀態）\n│   ├── userPreferences.ts\n│   └── ui.ts\n└── composables\u002F          # 組合式函式\n","text",[214,334,331],{"__ignoreMap":212},[45,336,338],{"id":337},"queries-vs-stores-的分工","queries\u002F vs stores\u002F 的分工",[50,340,341,354],{},[53,342,343],{},[56,344,345,348,351],{},[59,346,347],{},"目錄",[59,349,350],{},"用途",[59,352,353],{},"範例",[69,355,356,369],{},[56,357,358,363,366],{},[74,359,360],{},[214,361,362],{},"queries\u002F",[74,364,365],{},"Server 資料快取",[74,367,368],{},"列表、單筆資料、下拉選項",[56,370,371,376,379],{},[74,372,373],{},[214,374,375],{},"stores\u002F",[74,377,378],{},"Client 狀態",[74,380,381],{},"使用者偏好、UI 狀態",[38,383],{},[11,385,387],{"id":386},"usequery-查詢","useQuery 查詢",[45,389,390],{"id":390},"基本用法",[207,392,394],{"className":238,"code":393,"language":240,"meta":212,"style":212},"\u002F\u002F app\u002Fqueries\u002Fusers.ts\nimport { useQuery } from \"@pinia\u002Fcolada\";\n\nexport function useUsersQuery() {\n  return useQuery({\n    key: [\"users\"],\n    query: () => $fetch(\"\u002Fapi\u002Fv1\u002Fusers\"),\n  });\n}\n\n\u002F\u002F 在元件中使用\nconst { data, status, error, refetch } = useUsersQuery();\n",[214,395,396,401,427,433,450,462,483,513,523,529,534,540],{"__ignoreMap":212},[217,397,398],{"class":219,"line":220},[217,399,400],{"class":247},"\u002F\u002F app\u002Fqueries\u002Fusers.ts\n",[217,402,403,406,409,412,415,418,420,423,425],{"class":219,"line":251},[217,404,405],{"class":254},"import",[217,407,408],{"class":269}," {",[217,410,411],{"class":265}," useQuery",[217,413,414],{"class":269}," }",[217,416,417],{"class":254}," from",[217,419,298],{"class":286},[217,421,422],{"class":227},"@pinia\u002Fcolada",[217,424,287],{"class":286},[217,426,321],{"class":269},[217,428,429],{"class":219,"line":273},[217,430,432],{"emptyLinePlaceholder":431},true,"\n",[217,434,435,437,441,444,447],{"class":219,"line":312},[217,436,255],{"class":254},[217,438,440],{"class":439},"sbsja"," function",[217,442,443],{"class":261}," useUsersQuery",[217,445,446],{"class":269},"()",[217,448,449],{"class":269}," {\n",[217,451,453,456,458,460],{"class":219,"line":452},5,[217,454,455],{"class":254},"  return",[217,457,411],{"class":261},[217,459,266],{"class":276},[217,461,270],{"class":269},[217,463,465,468,470,472,474,477,479,481],{"class":219,"line":464},6,[217,466,467],{"class":276},"    key",[217,469,280],{"class":269},[217,471,283],{"class":276},[217,473,287],{"class":286},[217,475,476],{"class":227},"users",[217,478,287],{"class":286},[217,480,306],{"class":276},[217,482,309],{"class":269},[217,484,486,489,491,494,497,500,502,504,507,509,511],{"class":219,"line":485},7,[217,487,488],{"class":261},"    query",[217,490,280],{"class":269},[217,492,493],{"class":269}," ()",[217,495,496],{"class":439}," =>",[217,498,499],{"class":261}," $fetch",[217,501,266],{"class":276},[217,503,287],{"class":286},[217,505,506],{"class":227},"\u002Fapi\u002Fv1\u002Fusers",[217,508,287],{"class":286},[217,510,318],{"class":276},[217,512,309],{"class":269},[217,514,516,519,521],{"class":219,"line":515},8,[217,517,518],{"class":269},"  }",[217,520,318],{"class":276},[217,522,321],{"class":269},[217,524,526],{"class":219,"line":525},9,[217,527,528],{"class":269},"}\n",[217,530,532],{"class":219,"line":531},10,[217,533,432],{"emptyLinePlaceholder":431},[217,535,537],{"class":219,"line":536},11,[217,538,539],{"class":247},"\u002F\u002F 在元件中使用\n",[217,541,543,546,548,552,554,557,559,562,564,567,569,573,575,577],{"class":219,"line":542},12,[217,544,545],{"class":439},"const",[217,547,408],{"class":269},[217,549,551],{"class":550},"s_hVV"," data",[217,553,295],{"class":269},[217,555,556],{"class":550}," status",[217,558,295],{"class":269},[217,560,561],{"class":550}," error",[217,563,295],{"class":269},[217,565,566],{"class":550}," refetch",[217,568,414],{"class":269},[217,570,572],{"class":571},"smGrS"," =",[217,574,443],{"class":261},[217,576,446],{"class":265},[217,578,321],{"class":269},[45,580,581],{"id":581},"回傳值說明",[50,583,584,597],{},[53,585,586],{},[56,587,588,591,594],{},[59,589,590],{},"屬性",[59,592,593],{},"類型",[59,595,596],{},"說明",[69,598,599,614,629,644,659],{},[56,600,601,606,611],{},[74,602,603],{},[214,604,605],{},"data",[74,607,608],{},[214,609,610],{},"Ref&lt;T | undefined&gt;",[74,612,613],{},"查詢結果",[56,615,616,621,626],{},[74,617,618],{},[214,619,620],{},"status",[74,622,623],{},[214,624,625],{},"Ref&lt;'pending' | 'success' | 'error'&gt;",[74,627,628],{},"查詢狀態",[56,630,631,636,641],{},[74,632,633],{},[214,634,635],{},"error",[74,637,638],{},[214,639,640],{},"Ref&lt;Error | null&gt;",[74,642,643],{},"錯誤物件",[56,645,646,651,656],{},[74,647,648],{},[214,649,650],{},"isLoading",[74,652,653],{},[214,654,655],{},"ComputedRef&lt;boolean&gt;",[74,657,658],{},"是否載入中",[56,660,661,666,671],{},[74,662,663],{},[214,664,665],{},"refetch",[74,667,668],{},[214,669,670],{},"() =&gt; Promise",[74,672,673],{},"手動重新查詢",[45,675,676],{"id":676},"帶參數的查詢",[207,678,680],{"className":238,"code":679,"language":240,"meta":212,"style":212},"export function useUserQuery(userId: MaybeRefOrGetter&lt;string&gt;) {\n  return useQuery({\n    key: () => ['users', toValue(userId)],\n    query: () => $fetch(`\u002Fapi\u002Fv1\u002Fusers\u002F${toValue(userId)}`),\n    \u002F\u002F userId 變化時自動重新查詢\n  })\n}\n\n\u002F\u002F 使用\nconst userId = ref('123')\nconst { data: user } = useUserQuery(userId)\n\n\u002F\u002F 變更 userId 會自動觸發新查詢\nuserId.value = '456'\n",[214,681,682,726,736,769,809,814,821,825,829,834,857,880,884,890],{"__ignoreMap":212},[217,683,684,686,688,691,693,697,699,702,705,708,711,715,717,720,722,724],{"class":219,"line":220},[217,685,255],{"class":254},[217,687,440],{"class":439},[217,689,690],{"class":261}," useUserQuery",[217,692,266],{"class":269},[217,694,696],{"class":695},"s99_P","userId",[217,698,280],{"class":571},[217,700,701],{"class":223}," MaybeRefOrGetter",[217,703,704],{"class":571},"&",[217,706,707],{"class":223},"lt",[217,709,710],{"class":265},";",[217,712,714],{"class":713},"sZMiF","string",[217,716,704],{"class":571},[217,718,719],{"class":223},"gt",[217,721,710],{"class":265},[217,723,318],{"class":269},[217,725,449],{"class":269},[217,727,728,730,732,734],{"class":219,"line":251},[217,729,455],{"class":254},[217,731,411],{"class":261},[217,733,266],{"class":276},[217,735,270],{"class":269},[217,737,738,740,742,744,746,748,751,753,755,757,760,762,764,767],{"class":219,"line":273},[217,739,467],{"class":261},[217,741,280],{"class":269},[217,743,493],{"class":269},[217,745,496],{"class":439},[217,747,283],{"class":276},[217,749,750],{"class":286},"'",[217,752,476],{"class":227},[217,754,750],{"class":286},[217,756,295],{"class":269},[217,758,759],{"class":261}," toValue",[217,761,266],{"class":276},[217,763,696],{"class":265},[217,765,766],{"class":276},")]",[217,768,309],{"class":269},[217,770,771,773,775,777,779,781,783,786,789,792,795,798,800,802,805,807],{"class":219,"line":312},[217,772,488],{"class":261},[217,774,280],{"class":269},[217,776,493],{"class":269},[217,778,496],{"class":439},[217,780,499],{"class":261},[217,782,266],{"class":276},[217,784,785],{"class":286},"`",[217,787,788],{"class":227},"\u002Fapi\u002Fv1\u002Fusers\u002F",[217,790,791],{"class":286},"${",[217,793,794],{"class":261},"toValue",[217,796,266],{"class":797},"sfo-9",[217,799,696],{"class":265},[217,801,318],{"class":797},[217,803,804],{"class":286},"}`",[217,806,318],{"class":276},[217,808,309],{"class":269},[217,810,811],{"class":219,"line":452},[217,812,813],{"class":247},"    \u002F\u002F userId 變化時自動重新查詢\n",[217,815,816,818],{"class":219,"line":464},[217,817,518],{"class":269},[217,819,820],{"class":276},")\n",[217,822,823],{"class":219,"line":485},[217,824,528],{"class":269},[217,826,827],{"class":219,"line":515},[217,828,432],{"emptyLinePlaceholder":431},[217,830,831],{"class":219,"line":525},[217,832,833],{"class":247},"\u002F\u002F 使用\n",[217,835,836,838,841,843,846,848,850,853,855],{"class":219,"line":531},[217,837,545],{"class":439},[217,839,840],{"class":550}," userId",[217,842,572],{"class":571},[217,844,845],{"class":261}," ref",[217,847,266],{"class":265},[217,849,750],{"class":286},[217,851,852],{"class":227},"123",[217,854,750],{"class":286},[217,856,820],{"class":265},[217,858,859,861,863,866,868,871,873,875,877],{"class":219,"line":536},[217,860,545],{"class":439},[217,862,408],{"class":269},[217,864,551],{"class":865},"sucvu",[217,867,280],{"class":269},[217,869,870],{"class":550}," user",[217,872,414],{"class":269},[217,874,572],{"class":571},[217,876,690],{"class":261},[217,878,879],{"class":265},"(userId)\n",[217,881,882],{"class":219,"line":542},[217,883,432],{"emptyLinePlaceholder":431},[217,885,887],{"class":219,"line":886},13,[217,888,889],{"class":247},"\u002F\u002F 變更 userId 會自動觸發新查詢\n",[217,891,893,895,898,901,904,907,910],{"class":219,"line":892},14,[217,894,696],{"class":265},[217,896,897],{"class":269},".",[217,899,900],{"class":265},"value ",[217,902,903],{"class":571},"=",[217,905,906],{"class":286}," '",[217,908,909],{"class":227},"456",[217,911,912],{"class":286},"'\n",[45,914,915],{"id":915},"分頁查詢",[207,917,919],{"className":238,"code":918,"language":240,"meta":212,"style":212},"export function useUsersListQuery(params: {\n  page: MaybeRefOrGetter&lt;number&gt;\n  pageSize: MaybeRefOrGetter&lt;number&gt;\n  search?: MaybeRefOrGetter&lt;string&gt;\n}) {\n  return useQuery({\n    key: () => [\n      'users',\n      'list',\n      {\n        page: toValue(params.page),\n        pageSize: toValue(params.pageSize),\n        search: toValue(params.search),\n      },\n    ],\n    query: () =>\n      $fetch('\u002Fapi\u002Fv1\u002Fusers', {\n        query: {\n          page: toValue(params.page),\n          pageSize: toValue(params.pageSize),\n          search: toValue(params.search),\n        },\n      }),\n  })\n}\n",[214,920,921,939,963,986,1010,1017,1027,1040,1051,1062,1067,1089,1111,1133,1138,1146,1158,1176,1186,1208,1230,1252,1258,1268,1275],{"__ignoreMap":212},[217,922,923,925,927,930,932,935,937],{"class":219,"line":220},[217,924,255],{"class":254},[217,926,440],{"class":439},[217,928,929],{"class":261}," useUsersListQuery",[217,931,266],{"class":269},[217,933,934],{"class":695},"params",[217,936,280],{"class":571},[217,938,449],{"class":269},[217,940,941,944,946,948,950,952,954,957,959,961],{"class":219,"line":251},[217,942,943],{"class":865},"  page",[217,945,280],{"class":571},[217,947,701],{"class":223},[217,949,704],{"class":571},[217,951,707],{"class":223},[217,953,710],{"class":269},[217,955,956],{"class":713},"number",[217,958,704],{"class":571},[217,960,719],{"class":865},[217,962,321],{"class":269},[217,964,965,968,970,972,974,976,978,980,982,984],{"class":219,"line":273},[217,966,967],{"class":865},"  pageSize",[217,969,280],{"class":571},[217,971,701],{"class":223},[217,973,704],{"class":571},[217,975,707],{"class":223},[217,977,710],{"class":269},[217,979,956],{"class":713},[217,981,704],{"class":571},[217,983,719],{"class":865},[217,985,321],{"class":269},[217,987,988,991,994,996,998,1000,1002,1004,1006,1008],{"class":219,"line":312},[217,989,990],{"class":865},"  search",[217,992,993],{"class":571},"?:",[217,995,701],{"class":223},[217,997,704],{"class":571},[217,999,707],{"class":223},[217,1001,710],{"class":269},[217,1003,714],{"class":713},[217,1005,704],{"class":571},[217,1007,719],{"class":865},[217,1009,321],{"class":269},[217,1011,1012,1015],{"class":219,"line":452},[217,1013,1014],{"class":269},"})",[217,1016,449],{"class":269},[217,1018,1019,1021,1023,1025],{"class":219,"line":464},[217,1020,455],{"class":254},[217,1022,411],{"class":261},[217,1024,266],{"class":276},[217,1026,270],{"class":269},[217,1028,1029,1031,1033,1035,1037],{"class":219,"line":485},[217,1030,467],{"class":261},[217,1032,280],{"class":269},[217,1034,493],{"class":269},[217,1036,496],{"class":439},[217,1038,1039],{"class":276}," [\n",[217,1041,1042,1045,1047,1049],{"class":219,"line":515},[217,1043,1044],{"class":286},"      '",[217,1046,476],{"class":227},[217,1048,750],{"class":286},[217,1050,309],{"class":269},[217,1052,1053,1055,1058,1060],{"class":219,"line":525},[217,1054,1044],{"class":286},[217,1056,1057],{"class":227},"list",[217,1059,750],{"class":286},[217,1061,309],{"class":269},[217,1063,1064],{"class":219,"line":531},[217,1065,1066],{"class":269},"      {\n",[217,1068,1069,1072,1074,1076,1078,1080,1082,1085,1087],{"class":219,"line":536},[217,1070,1071],{"class":276},"        page",[217,1073,280],{"class":269},[217,1075,759],{"class":261},[217,1077,266],{"class":276},[217,1079,934],{"class":265},[217,1081,897],{"class":269},[217,1083,1084],{"class":265},"page",[217,1086,318],{"class":276},[217,1088,309],{"class":269},[217,1090,1091,1094,1096,1098,1100,1102,1104,1107,1109],{"class":219,"line":542},[217,1092,1093],{"class":276},"        pageSize",[217,1095,280],{"class":269},[217,1097,759],{"class":261},[217,1099,266],{"class":276},[217,1101,934],{"class":265},[217,1103,897],{"class":269},[217,1105,1106],{"class":265},"pageSize",[217,1108,318],{"class":276},[217,1110,309],{"class":269},[217,1112,1113,1116,1118,1120,1122,1124,1126,1129,1131],{"class":219,"line":886},[217,1114,1115],{"class":276},"        search",[217,1117,280],{"class":269},[217,1119,759],{"class":261},[217,1121,266],{"class":276},[217,1123,934],{"class":265},[217,1125,897],{"class":269},[217,1127,1128],{"class":265},"search",[217,1130,318],{"class":276},[217,1132,309],{"class":269},[217,1134,1135],{"class":219,"line":892},[217,1136,1137],{"class":269},"      },\n",[217,1139,1141,1144],{"class":219,"line":1140},15,[217,1142,1143],{"class":276},"    ]",[217,1145,309],{"class":269},[217,1147,1149,1151,1153,1155],{"class":219,"line":1148},16,[217,1150,488],{"class":261},[217,1152,280],{"class":269},[217,1154,493],{"class":269},[217,1156,1157],{"class":439}," =>\n",[217,1159,1161,1164,1166,1168,1170,1172,1174],{"class":219,"line":1160},17,[217,1162,1163],{"class":261},"      $fetch",[217,1165,266],{"class":276},[217,1167,750],{"class":286},[217,1169,506],{"class":227},[217,1171,750],{"class":286},[217,1173,295],{"class":269},[217,1175,449],{"class":269},[217,1177,1179,1182,1184],{"class":219,"line":1178},18,[217,1180,1181],{"class":276},"        query",[217,1183,280],{"class":269},[217,1185,449],{"class":269},[217,1187,1189,1192,1194,1196,1198,1200,1202,1204,1206],{"class":219,"line":1188},19,[217,1190,1191],{"class":276},"          page",[217,1193,280],{"class":269},[217,1195,759],{"class":261},[217,1197,266],{"class":276},[217,1199,934],{"class":265},[217,1201,897],{"class":269},[217,1203,1084],{"class":265},[217,1205,318],{"class":276},[217,1207,309],{"class":269},[217,1209,1211,1214,1216,1218,1220,1222,1224,1226,1228],{"class":219,"line":1210},20,[217,1212,1213],{"class":276},"          pageSize",[217,1215,280],{"class":269},[217,1217,759],{"class":261},[217,1219,266],{"class":276},[217,1221,934],{"class":265},[217,1223,897],{"class":269},[217,1225,1106],{"class":265},[217,1227,318],{"class":276},[217,1229,309],{"class":269},[217,1231,1233,1236,1238,1240,1242,1244,1246,1248,1250],{"class":219,"line":1232},21,[217,1234,1235],{"class":276},"          search",[217,1237,280],{"class":269},[217,1239,759],{"class":261},[217,1241,266],{"class":276},[217,1243,934],{"class":265},[217,1245,897],{"class":269},[217,1247,1128],{"class":265},[217,1249,318],{"class":276},[217,1251,309],{"class":269},[217,1253,1255],{"class":219,"line":1254},22,[217,1256,1257],{"class":269},"        },\n",[217,1259,1261,1264,1266],{"class":219,"line":1260},23,[217,1262,1263],{"class":269},"      }",[217,1265,318],{"class":276},[217,1267,309],{"class":269},[217,1269,1271,1273],{"class":219,"line":1270},24,[217,1272,518],{"class":269},[217,1274,820],{"class":276},[217,1276,1278],{"class":219,"line":1277},25,[217,1279,528],{"class":269},[45,1281,1282],{"id":1282},"下拉選單選項查詢",[207,1284,1286],{"className":238,"code":1285,"language":240,"meta":212,"style":212},"\u002F\u002F app\u002Fqueries\u002Foptions.ts\nexport function useRoleOptionsQuery() {\n  return useQuery({\n    key: ['options', 'roles'],\n    query: async () => {\n      const client = useSupabaseClient&lt;Database&gt;()\n      const { data } = await client\n        .from('roles')\n        .select('id, name')\n        .order('name')\n      return data || []\n    },\n    staleTime: 10 * 60 * 1000, \u002F\u002F 選項較少變動，快取 10 分鐘\n  })\n}\n",[214,1287,1288,1293,1306,1316,1344,1359,1390,1408,1426,1444,1462,1475,1480,1507,1513],{"__ignoreMap":212},[217,1289,1290],{"class":219,"line":220},[217,1291,1292],{"class":247},"\u002F\u002F app\u002Fqueries\u002Foptions.ts\n",[217,1294,1295,1297,1299,1302,1304],{"class":219,"line":251},[217,1296,255],{"class":254},[217,1298,440],{"class":439},[217,1300,1301],{"class":261}," useRoleOptionsQuery",[217,1303,446],{"class":269},[217,1305,449],{"class":269},[217,1307,1308,1310,1312,1314],{"class":219,"line":273},[217,1309,455],{"class":254},[217,1311,411],{"class":261},[217,1313,266],{"class":276},[217,1315,270],{"class":269},[217,1317,1318,1320,1322,1324,1326,1329,1331,1333,1335,1338,1340,1342],{"class":219,"line":312},[217,1319,467],{"class":276},[217,1321,280],{"class":269},[217,1323,283],{"class":276},[217,1325,750],{"class":286},[217,1327,1328],{"class":227},"options",[217,1330,750],{"class":286},[217,1332,295],{"class":269},[217,1334,906],{"class":286},[217,1336,1337],{"class":227},"roles",[217,1339,750],{"class":286},[217,1341,306],{"class":276},[217,1343,309],{"class":269},[217,1345,1346,1348,1350,1353,1355,1357],{"class":219,"line":452},[217,1347,488],{"class":261},[217,1349,280],{"class":269},[217,1351,1352],{"class":439}," async",[217,1354,493],{"class":269},[217,1356,496],{"class":439},[217,1358,449],{"class":269},[217,1360,1361,1364,1367,1369,1372,1374,1376,1378,1381,1383,1385,1387],{"class":219,"line":464},[217,1362,1363],{"class":439},"      const",[217,1365,1366],{"class":550}," client",[217,1368,572],{"class":571},[217,1370,1371],{"class":265}," useSupabaseClient",[217,1373,704],{"class":571},[217,1375,707],{"class":265},[217,1377,710],{"class":269},[217,1379,1380],{"class":265},"Database",[217,1382,704],{"class":571},[217,1384,719],{"class":265},[217,1386,710],{"class":269},[217,1388,1389],{"class":276},"()\n",[217,1391,1392,1394,1396,1398,1400,1402,1405],{"class":219,"line":485},[217,1393,1363],{"class":439},[217,1395,408],{"class":269},[217,1397,551],{"class":550},[217,1399,414],{"class":269},[217,1401,572],{"class":571},[217,1403,1404],{"class":254}," await",[217,1406,1407],{"class":265}," client\n",[217,1409,1410,1413,1416,1418,1420,1422,1424],{"class":219,"line":515},[217,1411,1412],{"class":269},"        .",[217,1414,1415],{"class":261},"from",[217,1417,266],{"class":276},[217,1419,750],{"class":286},[217,1421,1337],{"class":227},[217,1423,750],{"class":286},[217,1425,820],{"class":276},[217,1427,1428,1430,1433,1435,1437,1440,1442],{"class":219,"line":525},[217,1429,1412],{"class":269},[217,1431,1432],{"class":261},"select",[217,1434,266],{"class":276},[217,1436,750],{"class":286},[217,1438,1439],{"class":227},"id, name",[217,1441,750],{"class":286},[217,1443,820],{"class":276},[217,1445,1446,1448,1451,1453,1455,1458,1460],{"class":219,"line":531},[217,1447,1412],{"class":269},[217,1449,1450],{"class":261},"order",[217,1452,266],{"class":276},[217,1454,750],{"class":286},[217,1456,1457],{"class":227},"name",[217,1459,750],{"class":286},[217,1461,820],{"class":276},[217,1463,1464,1467,1469,1472],{"class":219,"line":536},[217,1465,1466],{"class":254},"      return",[217,1468,551],{"class":265},[217,1470,1471],{"class":571}," ||",[217,1473,1474],{"class":276}," []\n",[217,1476,1477],{"class":219,"line":542},[217,1478,1479],{"class":269},"    },\n",[217,1481,1482,1485,1487,1491,1494,1497,1499,1502,1504],{"class":219,"line":886},[217,1483,1484],{"class":276},"    staleTime",[217,1486,280],{"class":269},[217,1488,1490],{"class":1489},"srdBf"," 10",[217,1492,1493],{"class":571}," *",[217,1495,1496],{"class":1489}," 60",[217,1498,1493],{"class":571},[217,1500,1501],{"class":1489}," 1000",[217,1503,295],{"class":269},[217,1505,1506],{"class":247}," \u002F\u002F 選項較少變動，快取 10 分鐘\n",[217,1508,1509,1511],{"class":219,"line":892},[217,1510,518],{"class":269},[217,1512,820],{"class":276},[217,1514,1515],{"class":219,"line":1140},[217,1516,528],{"class":269},[38,1518],{},[11,1520,1522],{"id":1521},"usemutation-變更","useMutation 變更",[45,1524,390],{"id":1525},"基本用法-1",[207,1527,1529],{"className":238,"code":1528,"language":240,"meta":212,"style":212},"import { useMutation, useQueryClient } from \"@pinia\u002Fcolada\";\n\nexport function useCreateUserMutation() {\n  const queryClient = useQueryClient();\n\n  return useMutation({\n    mutation: (data: CreateUserInput) =>\n      $fetch(\"\u002Fapi\u002Fv1\u002Fusers\", {\n        method: \"POST\",\n        body: data,\n      }),\n    onSuccess: () => {\n      \u002F\u002F 成功後使 users 列表快取失效\n      queryClient.invalidateQueries({ key: [\"users\"] });\n    },\n  });\n}\n",[214,1530,1531,1557,1561,1574,1590,1594,1604,1625,1641,1657,1668,1676,1689,1694,1731,1735,1743],{"__ignoreMap":212},[217,1532,1533,1535,1537,1540,1542,1545,1547,1549,1551,1553,1555],{"class":219,"line":220},[217,1534,405],{"class":254},[217,1536,408],{"class":269},[217,1538,1539],{"class":265}," useMutation",[217,1541,295],{"class":269},[217,1543,1544],{"class":265}," useQueryClient",[217,1546,414],{"class":269},[217,1548,417],{"class":254},[217,1550,298],{"class":286},[217,1552,422],{"class":227},[217,1554,287],{"class":286},[217,1556,321],{"class":269},[217,1558,1559],{"class":219,"line":251},[217,1560,432],{"emptyLinePlaceholder":431},[217,1562,1563,1565,1567,1570,1572],{"class":219,"line":273},[217,1564,255],{"class":254},[217,1566,440],{"class":439},[217,1568,1569],{"class":261}," useCreateUserMutation",[217,1571,446],{"class":269},[217,1573,449],{"class":269},[217,1575,1576,1579,1582,1584,1586,1588],{"class":219,"line":312},[217,1577,1578],{"class":439},"  const",[217,1580,1581],{"class":550}," queryClient",[217,1583,572],{"class":571},[217,1585,1544],{"class":261},[217,1587,446],{"class":276},[217,1589,321],{"class":269},[217,1591,1592],{"class":219,"line":452},[217,1593,432],{"emptyLinePlaceholder":431},[217,1595,1596,1598,1600,1602],{"class":219,"line":464},[217,1597,455],{"class":254},[217,1599,1539],{"class":261},[217,1601,266],{"class":276},[217,1603,270],{"class":269},[217,1605,1606,1609,1611,1614,1616,1618,1621,1623],{"class":219,"line":485},[217,1607,1608],{"class":261},"    mutation",[217,1610,280],{"class":269},[217,1612,1613],{"class":269}," (",[217,1615,605],{"class":695},[217,1617,280],{"class":571},[217,1619,1620],{"class":223}," CreateUserInput",[217,1622,318],{"class":269},[217,1624,1157],{"class":439},[217,1626,1627,1629,1631,1633,1635,1637,1639],{"class":219,"line":515},[217,1628,1163],{"class":261},[217,1630,266],{"class":276},[217,1632,287],{"class":286},[217,1634,506],{"class":227},[217,1636,287],{"class":286},[217,1638,295],{"class":269},[217,1640,449],{"class":269},[217,1642,1643,1646,1648,1650,1653,1655],{"class":219,"line":525},[217,1644,1645],{"class":276},"        method",[217,1647,280],{"class":269},[217,1649,298],{"class":286},[217,1651,1652],{"class":227},"POST",[217,1654,287],{"class":286},[217,1656,309],{"class":269},[217,1658,1659,1662,1664,1666],{"class":219,"line":531},[217,1660,1661],{"class":276},"        body",[217,1663,280],{"class":269},[217,1665,551],{"class":265},[217,1667,309],{"class":269},[217,1669,1670,1672,1674],{"class":219,"line":536},[217,1671,1263],{"class":269},[217,1673,318],{"class":276},[217,1675,309],{"class":269},[217,1677,1678,1681,1683,1685,1687],{"class":219,"line":542},[217,1679,1680],{"class":261},"    onSuccess",[217,1682,280],{"class":269},[217,1684,493],{"class":269},[217,1686,496],{"class":439},[217,1688,449],{"class":269},[217,1690,1691],{"class":219,"line":886},[217,1692,1693],{"class":247},"      \u002F\u002F 成功後使 users 列表快取失效\n",[217,1695,1696,1699,1701,1704,1706,1709,1712,1714,1716,1718,1720,1722,1725,1727,1729],{"class":219,"line":892},[217,1697,1698],{"class":265},"      queryClient",[217,1700,897],{"class":269},[217,1702,1703],{"class":261},"invalidateQueries",[217,1705,266],{"class":276},[217,1707,1708],{"class":269},"{",[217,1710,1711],{"class":276}," key",[217,1713,280],{"class":269},[217,1715,283],{"class":276},[217,1717,287],{"class":286},[217,1719,476],{"class":227},[217,1721,287],{"class":286},[217,1723,1724],{"class":276},"] ",[217,1726,315],{"class":269},[217,1728,318],{"class":276},[217,1730,321],{"class":269},[217,1732,1733],{"class":219,"line":1140},[217,1734,1479],{"class":269},[217,1736,1737,1739,1741],{"class":219,"line":1148},[217,1738,518],{"class":269},[217,1740,318],{"class":276},[217,1742,321],{"class":269},[217,1744,1745],{"class":219,"line":1160},[217,1746,528],{"class":269},[45,1748,1749],{"id":1749},"在元件中使用",[207,1751,1755],{"className":1752,"code":1753,"language":1754,"meta":212,"style":212},"language-vue shiki shiki-themes material-theme-lighter github-light github-dark","&lt;script setup lang=\"ts\"&gt; const { mutate, status, error } =\nuseCreateUserMutation() const toast = useToast() async function\nhandleSubmit(formData: CreateUserInput) { try { await mutate(formData)\ntoast.add({ title: '新增成功', color: 'green' }) } catch (e) { toast.add({\ntitle: '新增失敗', color: 'red' }) } } &lt;\u002Fscript&gt;\n","vue",[214,1756,1757,1762,1767,1772,1777],{"__ignoreMap":212},[217,1758,1759],{"class":219,"line":220},[217,1760,1761],{"class":265},"&lt;script setup lang=\"ts\"&gt; const { mutate, status, error } =\n",[217,1763,1764],{"class":219,"line":251},[217,1765,1766],{"class":265},"useCreateUserMutation() const toast = useToast() async function\n",[217,1768,1769],{"class":219,"line":273},[217,1770,1771],{"class":265},"handleSubmit(formData: CreateUserInput) { try { await mutate(formData)\n",[217,1773,1774],{"class":219,"line":312},[217,1775,1776],{"class":265},"toast.add({ title: '新增成功', color: 'green' }) } catch (e) { toast.add({\n",[217,1778,1779],{"class":219,"line":452},[217,1780,1781],{"class":265},"title: '新增失敗', color: 'red' }) } } &lt;\u002Fscript&gt;\n",[45,1783,1784],{"id":1784},"更新與刪除",[207,1786,1788],{"className":238,"code":1787,"language":240,"meta":212,"style":212},"\u002F\u002F 更新\nexport function useUpdateUserMutation() {\n  const queryClient = useQueryClient();\n\n  return useMutation({\n    mutation: ({ id, data }: { id: string; data: UpdateUserInput }) =>\n      $fetch(`\u002Fapi\u002Fv1\u002Fusers\u002F${id}`, {\n        method: \"PATCH\",\n        body: data,\n      }),\n    onSuccess: (result, { id }) => {\n      \u002F\u002F 使單筆和列表快取都失效\n      queryClient.invalidateQueries({ key: [\"users\", id] });\n      queryClient.invalidateQueries({ key: [\"users\", \"list\"] });\n    },\n  });\n}\n\n\u002F\u002F 刪除\nexport function useDeleteUserMutation() {\n  const queryClient = useQueryClient();\n\n  return useMutation({\n    mutation: (id: string) =>\n      $fetch(`\u002Fapi\u002Fv1\u002Fusers\u002F${id}`, {\n        method: \"DELETE\",\n      }),\n    onSuccess: () => {\n      queryClient.invalidateQueries({ key: [\"users\"] });\n    },\n  });\n}\n",[214,1789,1790,1795,1808,1822,1826,1836,1879,1900,1915,1925,1933,1956,1961,1997,2037,2041,2049,2053,2057,2062,2075,2089,2093,2103,2121,2141,2157,2166,2179,2212,2217,2226],{"__ignoreMap":212},[217,1791,1792],{"class":219,"line":220},[217,1793,1794],{"class":247},"\u002F\u002F 更新\n",[217,1796,1797,1799,1801,1804,1806],{"class":219,"line":251},[217,1798,255],{"class":254},[217,1800,440],{"class":439},[217,1802,1803],{"class":261}," useUpdateUserMutation",[217,1805,446],{"class":269},[217,1807,449],{"class":269},[217,1809,1810,1812,1814,1816,1818,1820],{"class":219,"line":273},[217,1811,1578],{"class":439},[217,1813,1581],{"class":550},[217,1815,572],{"class":571},[217,1817,1544],{"class":261},[217,1819,446],{"class":276},[217,1821,321],{"class":269},[217,1823,1824],{"class":219,"line":312},[217,1825,432],{"emptyLinePlaceholder":431},[217,1827,1828,1830,1832,1834],{"class":219,"line":452},[217,1829,455],{"class":254},[217,1831,1539],{"class":261},[217,1833,266],{"class":276},[217,1835,270],{"class":269},[217,1837,1838,1840,1842,1845,1848,1850,1852,1854,1856,1858,1860,1862,1865,1867,1869,1871,1874,1877],{"class":219,"line":464},[217,1839,1608],{"class":261},[217,1841,280],{"class":269},[217,1843,1844],{"class":269}," ({",[217,1846,1847],{"class":695}," id",[217,1849,295],{"class":269},[217,1851,551],{"class":695},[217,1853,414],{"class":269},[217,1855,280],{"class":571},[217,1857,408],{"class":269},[217,1859,1847],{"class":865},[217,1861,280],{"class":571},[217,1863,1864],{"class":713}," string",[217,1866,710],{"class":269},[217,1868,551],{"class":865},[217,1870,280],{"class":571},[217,1872,1873],{"class":223}," UpdateUserInput",[217,1875,1876],{"class":269}," })",[217,1878,1157],{"class":439},[217,1880,1881,1883,1885,1887,1889,1891,1894,1896,1898],{"class":219,"line":485},[217,1882,1163],{"class":261},[217,1884,266],{"class":276},[217,1886,785],{"class":286},[217,1888,788],{"class":227},[217,1890,791],{"class":286},[217,1892,1893],{"class":265},"id",[217,1895,804],{"class":286},[217,1897,295],{"class":269},[217,1899,449],{"class":269},[217,1901,1902,1904,1906,1908,1911,1913],{"class":219,"line":515},[217,1903,1645],{"class":276},[217,1905,280],{"class":269},[217,1907,298],{"class":286},[217,1909,1910],{"class":227},"PATCH",[217,1912,287],{"class":286},[217,1914,309],{"class":269},[217,1916,1917,1919,1921,1923],{"class":219,"line":525},[217,1918,1661],{"class":276},[217,1920,280],{"class":269},[217,1922,551],{"class":265},[217,1924,309],{"class":269},[217,1926,1927,1929,1931],{"class":219,"line":531},[217,1928,1263],{"class":269},[217,1930,318],{"class":276},[217,1932,309],{"class":269},[217,1934,1935,1937,1939,1941,1944,1946,1948,1950,1952,1954],{"class":219,"line":536},[217,1936,1680],{"class":261},[217,1938,280],{"class":269},[217,1940,1613],{"class":269},[217,1942,1943],{"class":695},"result",[217,1945,295],{"class":269},[217,1947,408],{"class":269},[217,1949,1847],{"class":695},[217,1951,1876],{"class":269},[217,1953,496],{"class":439},[217,1955,449],{"class":269},[217,1957,1958],{"class":219,"line":542},[217,1959,1960],{"class":247},"      \u002F\u002F 使單筆和列表快取都失效\n",[217,1962,1963,1965,1967,1969,1971,1973,1975,1977,1979,1981,1983,1985,1987,1989,1991,1993,1995],{"class":219,"line":886},[217,1964,1698],{"class":265},[217,1966,897],{"class":269},[217,1968,1703],{"class":261},[217,1970,266],{"class":276},[217,1972,1708],{"class":269},[217,1974,1711],{"class":276},[217,1976,280],{"class":269},[217,1978,283],{"class":276},[217,1980,287],{"class":286},[217,1982,476],{"class":227},[217,1984,287],{"class":286},[217,1986,295],{"class":269},[217,1988,1847],{"class":265},[217,1990,1724],{"class":276},[217,1992,315],{"class":269},[217,1994,318],{"class":276},[217,1996,321],{"class":269},[217,1998,1999,2001,2003,2005,2007,2009,2011,2013,2015,2017,2019,2021,2023,2025,2027,2029,2031,2033,2035],{"class":219,"line":892},[217,2000,1698],{"class":265},[217,2002,897],{"class":269},[217,2004,1703],{"class":261},[217,2006,266],{"class":276},[217,2008,1708],{"class":269},[217,2010,1711],{"class":276},[217,2012,280],{"class":269},[217,2014,283],{"class":276},[217,2016,287],{"class":286},[217,2018,476],{"class":227},[217,2020,287],{"class":286},[217,2022,295],{"class":269},[217,2024,298],{"class":286},[217,2026,1057],{"class":227},[217,2028,287],{"class":286},[217,2030,1724],{"class":276},[217,2032,315],{"class":269},[217,2034,318],{"class":276},[217,2036,321],{"class":269},[217,2038,2039],{"class":219,"line":1140},[217,2040,1479],{"class":269},[217,2042,2043,2045,2047],{"class":219,"line":1148},[217,2044,518],{"class":269},[217,2046,318],{"class":276},[217,2048,321],{"class":269},[217,2050,2051],{"class":219,"line":1160},[217,2052,528],{"class":269},[217,2054,2055],{"class":219,"line":1178},[217,2056,432],{"emptyLinePlaceholder":431},[217,2058,2059],{"class":219,"line":1188},[217,2060,2061],{"class":247},"\u002F\u002F 刪除\n",[217,2063,2064,2066,2068,2071,2073],{"class":219,"line":1210},[217,2065,255],{"class":254},[217,2067,440],{"class":439},[217,2069,2070],{"class":261}," useDeleteUserMutation",[217,2072,446],{"class":269},[217,2074,449],{"class":269},[217,2076,2077,2079,2081,2083,2085,2087],{"class":219,"line":1232},[217,2078,1578],{"class":439},[217,2080,1581],{"class":550},[217,2082,572],{"class":571},[217,2084,1544],{"class":261},[217,2086,446],{"class":276},[217,2088,321],{"class":269},[217,2090,2091],{"class":219,"line":1254},[217,2092,432],{"emptyLinePlaceholder":431},[217,2094,2095,2097,2099,2101],{"class":219,"line":1260},[217,2096,455],{"class":254},[217,2098,1539],{"class":261},[217,2100,266],{"class":276},[217,2102,270],{"class":269},[217,2104,2105,2107,2109,2111,2113,2115,2117,2119],{"class":219,"line":1270},[217,2106,1608],{"class":261},[217,2108,280],{"class":269},[217,2110,1613],{"class":269},[217,2112,1893],{"class":695},[217,2114,280],{"class":571},[217,2116,1864],{"class":713},[217,2118,318],{"class":269},[217,2120,1157],{"class":439},[217,2122,2123,2125,2127,2129,2131,2133,2135,2137,2139],{"class":219,"line":1277},[217,2124,1163],{"class":261},[217,2126,266],{"class":276},[217,2128,785],{"class":286},[217,2130,788],{"class":227},[217,2132,791],{"class":286},[217,2134,1893],{"class":265},[217,2136,804],{"class":286},[217,2138,295],{"class":269},[217,2140,449],{"class":269},[217,2142,2144,2146,2148,2150,2153,2155],{"class":219,"line":2143},26,[217,2145,1645],{"class":276},[217,2147,280],{"class":269},[217,2149,298],{"class":286},[217,2151,2152],{"class":227},"DELETE",[217,2154,287],{"class":286},[217,2156,309],{"class":269},[217,2158,2160,2162,2164],{"class":219,"line":2159},27,[217,2161,1263],{"class":269},[217,2163,318],{"class":276},[217,2165,309],{"class":269},[217,2167,2169,2171,2173,2175,2177],{"class":219,"line":2168},28,[217,2170,1680],{"class":261},[217,2172,280],{"class":269},[217,2174,493],{"class":269},[217,2176,496],{"class":439},[217,2178,449],{"class":269},[217,2180,2182,2184,2186,2188,2190,2192,2194,2196,2198,2200,2202,2204,2206,2208,2210],{"class":219,"line":2181},29,[217,2183,1698],{"class":265},[217,2185,897],{"class":269},[217,2187,1703],{"class":261},[217,2189,266],{"class":276},[217,2191,1708],{"class":269},[217,2193,1711],{"class":276},[217,2195,280],{"class":269},[217,2197,283],{"class":276},[217,2199,287],{"class":286},[217,2201,476],{"class":227},[217,2203,287],{"class":286},[217,2205,1724],{"class":276},[217,2207,315],{"class":269},[217,2209,318],{"class":276},[217,2211,321],{"class":269},[217,2213,2215],{"class":219,"line":2214},30,[217,2216,1479],{"class":269},[217,2218,2220,2222,2224],{"class":219,"line":2219},31,[217,2221,518],{"class":269},[217,2223,318],{"class":276},[217,2225,321],{"class":269},[217,2227,2229],{"class":219,"line":2228},32,[217,2230,528],{"class":269},[38,2232],{},[11,2234,193],{"id":193},[45,2236,2237],{"id":2237},"提升使用者體驗",[15,2239,2240],{},"樂觀更新在請求發送前就更新 UI，讓操作感覺更即時：",[207,2242,2244],{"className":238,"code":2243,"language":240,"meta":212,"style":212},"export function useUpdateUserMutation() {\n  const queryClient = useQueryClient();\n\n  return useMutation({\n    mutation: ({ id, data }: { id: string; data: UpdateUserInput }) =>\n      $fetch(`\u002Fapi\u002Fv1\u002Fusers\u002F${id}`, {\n        method: \"PATCH\",\n        body: data,\n      }),\n\n    onMutate: async ({ id, data }) => {\n      \u002F\u002F 1. 取消正在進行的查詢（避免覆蓋樂觀更新）\n      await queryClient.cancelQueries({ key: [\"users\", id] });\n\n      \u002F\u002F 2. 保存舊資料（用於回滾）\n      const previousUser = queryClient.getQueryData([\"users\", id]);\n\n      \u002F\u002F 3. 樂觀更新快取\n      queryClient.setQueryData([\"users\", id], (old: User) => ({\n        ...old,\n        ...data,\n      }));\n\n      \u002F\u002F 4. 回傳 context 供 onError 使用\n      return { previousUser };\n    },\n\n    onError: (error, { id }, context) => {\n      \u002F\u002F 錯誤時回滾到舊資料\n      if (context?.previousUser) {\n        queryClient.setQueryData([\"users\", id], context.previousUser);\n      }\n    },\n\n    onSettled: (result, error, { id }) => {\n      \u002F\u002F 無論成功或失敗，最後都重新查詢確保資料正確\n      queryClient.invalidateQueries({ key: [\"users\", id] });\n    },\n  });\n}\n",[214,2245,2246,2258,2272,2276,2286,2324,2344,2358,2368,2376,2380,2403,2408,2448,2452,2457,2491,2495,2500,2543,2552,2560,2569,2573,2578,2589,2593,2597,2626,2631,2652,2687,2692,2697,2702,2730,2736,2773,2778,2787],{"__ignoreMap":212},[217,2247,2248,2250,2252,2254,2256],{"class":219,"line":220},[217,2249,255],{"class":254},[217,2251,440],{"class":439},[217,2253,1803],{"class":261},[217,2255,446],{"class":269},[217,2257,449],{"class":269},[217,2259,2260,2262,2264,2266,2268,2270],{"class":219,"line":251},[217,2261,1578],{"class":439},[217,2263,1581],{"class":550},[217,2265,572],{"class":571},[217,2267,1544],{"class":261},[217,2269,446],{"class":276},[217,2271,321],{"class":269},[217,2273,2274],{"class":219,"line":273},[217,2275,432],{"emptyLinePlaceholder":431},[217,2277,2278,2280,2282,2284],{"class":219,"line":312},[217,2279,455],{"class":254},[217,2281,1539],{"class":261},[217,2283,266],{"class":276},[217,2285,270],{"class":269},[217,2287,2288,2290,2292,2294,2296,2298,2300,2302,2304,2306,2308,2310,2312,2314,2316,2318,2320,2322],{"class":219,"line":452},[217,2289,1608],{"class":261},[217,2291,280],{"class":269},[217,2293,1844],{"class":269},[217,2295,1847],{"class":695},[217,2297,295],{"class":269},[217,2299,551],{"class":695},[217,2301,414],{"class":269},[217,2303,280],{"class":571},[217,2305,408],{"class":269},[217,2307,1847],{"class":865},[217,2309,280],{"class":571},[217,2311,1864],{"class":713},[217,2313,710],{"class":269},[217,2315,551],{"class":865},[217,2317,280],{"class":571},[217,2319,1873],{"class":223},[217,2321,1876],{"class":269},[217,2323,1157],{"class":439},[217,2325,2326,2328,2330,2332,2334,2336,2338,2340,2342],{"class":219,"line":464},[217,2327,1163],{"class":261},[217,2329,266],{"class":276},[217,2331,785],{"class":286},[217,2333,788],{"class":227},[217,2335,791],{"class":286},[217,2337,1893],{"class":265},[217,2339,804],{"class":286},[217,2341,295],{"class":269},[217,2343,449],{"class":269},[217,2345,2346,2348,2350,2352,2354,2356],{"class":219,"line":485},[217,2347,1645],{"class":276},[217,2349,280],{"class":269},[217,2351,298],{"class":286},[217,2353,1910],{"class":227},[217,2355,287],{"class":286},[217,2357,309],{"class":269},[217,2359,2360,2362,2364,2366],{"class":219,"line":515},[217,2361,1661],{"class":276},[217,2363,280],{"class":269},[217,2365,551],{"class":265},[217,2367,309],{"class":269},[217,2369,2370,2372,2374],{"class":219,"line":525},[217,2371,1263],{"class":269},[217,2373,318],{"class":276},[217,2375,309],{"class":269},[217,2377,2378],{"class":219,"line":531},[217,2379,432],{"emptyLinePlaceholder":431},[217,2381,2382,2385,2387,2389,2391,2393,2395,2397,2399,2401],{"class":219,"line":536},[217,2383,2384],{"class":261},"    onMutate",[217,2386,280],{"class":269},[217,2388,1352],{"class":439},[217,2390,1844],{"class":269},[217,2392,1847],{"class":695},[217,2394,295],{"class":269},[217,2396,551],{"class":695},[217,2398,1876],{"class":269},[217,2400,496],{"class":439},[217,2402,449],{"class":269},[217,2404,2405],{"class":219,"line":542},[217,2406,2407],{"class":247},"      \u002F\u002F 1. 取消正在進行的查詢（避免覆蓋樂觀更新）\n",[217,2409,2410,2413,2415,2417,2420,2422,2424,2426,2428,2430,2432,2434,2436,2438,2440,2442,2444,2446],{"class":219,"line":886},[217,2411,2412],{"class":254},"      await",[217,2414,1581],{"class":265},[217,2416,897],{"class":269},[217,2418,2419],{"class":261},"cancelQueries",[217,2421,266],{"class":276},[217,2423,1708],{"class":269},[217,2425,1711],{"class":276},[217,2427,280],{"class":269},[217,2429,283],{"class":276},[217,2431,287],{"class":286},[217,2433,476],{"class":227},[217,2435,287],{"class":286},[217,2437,295],{"class":269},[217,2439,1847],{"class":265},[217,2441,1724],{"class":276},[217,2443,315],{"class":269},[217,2445,318],{"class":276},[217,2447,321],{"class":269},[217,2449,2450],{"class":219,"line":892},[217,2451,432],{"emptyLinePlaceholder":431},[217,2453,2454],{"class":219,"line":1140},[217,2455,2456],{"class":247},"      \u002F\u002F 2. 保存舊資料（用於回滾）\n",[217,2458,2459,2461,2464,2466,2468,2470,2473,2476,2478,2480,2482,2484,2486,2489],{"class":219,"line":1148},[217,2460,1363],{"class":439},[217,2462,2463],{"class":550}," previousUser",[217,2465,572],{"class":571},[217,2467,1581],{"class":265},[217,2469,897],{"class":269},[217,2471,2472],{"class":261},"getQueryData",[217,2474,2475],{"class":276},"([",[217,2477,287],{"class":286},[217,2479,476],{"class":227},[217,2481,287],{"class":286},[217,2483,295],{"class":269},[217,2485,1847],{"class":265},[217,2487,2488],{"class":276},"])",[217,2490,321],{"class":269},[217,2492,2493],{"class":219,"line":1160},[217,2494,432],{"emptyLinePlaceholder":431},[217,2496,2497],{"class":219,"line":1178},[217,2498,2499],{"class":247},"      \u002F\u002F 3. 樂觀更新快取\n",[217,2501,2502,2504,2506,2509,2511,2513,2515,2517,2519,2521,2523,2525,2527,2530,2532,2535,2537,2539,2541],{"class":219,"line":1188},[217,2503,1698],{"class":265},[217,2505,897],{"class":269},[217,2507,2508],{"class":261},"setQueryData",[217,2510,2475],{"class":276},[217,2512,287],{"class":286},[217,2514,476],{"class":227},[217,2516,287],{"class":286},[217,2518,295],{"class":269},[217,2520,1847],{"class":265},[217,2522,306],{"class":276},[217,2524,295],{"class":269},[217,2526,1613],{"class":269},[217,2528,2529],{"class":695},"old",[217,2531,280],{"class":571},[217,2533,2534],{"class":223}," User",[217,2536,318],{"class":269},[217,2538,496],{"class":439},[217,2540,1613],{"class":276},[217,2542,270],{"class":269},[217,2544,2545,2548,2550],{"class":219,"line":1210},[217,2546,2547],{"class":571},"        ...",[217,2549,2529],{"class":265},[217,2551,309],{"class":269},[217,2553,2554,2556,2558],{"class":219,"line":1232},[217,2555,2547],{"class":571},[217,2557,605],{"class":265},[217,2559,309],{"class":269},[217,2561,2562,2564,2567],{"class":219,"line":1254},[217,2563,1263],{"class":269},[217,2565,2566],{"class":276},"))",[217,2568,321],{"class":269},[217,2570,2571],{"class":219,"line":1260},[217,2572,432],{"emptyLinePlaceholder":431},[217,2574,2575],{"class":219,"line":1270},[217,2576,2577],{"class":247},"      \u002F\u002F 4. 回傳 context 供 onError 使用\n",[217,2579,2580,2582,2584,2586],{"class":219,"line":1277},[217,2581,1466],{"class":254},[217,2583,408],{"class":269},[217,2585,2463],{"class":265},[217,2587,2588],{"class":269}," };\n",[217,2590,2591],{"class":219,"line":2143},[217,2592,1479],{"class":269},[217,2594,2595],{"class":219,"line":2159},[217,2596,432],{"emptyLinePlaceholder":431},[217,2598,2599,2602,2604,2606,2608,2610,2612,2614,2617,2620,2622,2624],{"class":219,"line":2168},[217,2600,2601],{"class":261},"    onError",[217,2603,280],{"class":269},[217,2605,1613],{"class":269},[217,2607,635],{"class":695},[217,2609,295],{"class":269},[217,2611,408],{"class":269},[217,2613,1847],{"class":695},[217,2615,2616],{"class":269}," },",[217,2618,2619],{"class":695}," context",[217,2621,318],{"class":269},[217,2623,496],{"class":439},[217,2625,449],{"class":269},[217,2627,2628],{"class":219,"line":2181},[217,2629,2630],{"class":247},"      \u002F\u002F 錯誤時回滾到舊資料\n",[217,2632,2633,2636,2638,2641,2644,2647,2650],{"class":219,"line":2214},[217,2634,2635],{"class":254},"      if",[217,2637,1613],{"class":276},[217,2639,2640],{"class":265},"context",[217,2642,2643],{"class":269},"?.",[217,2645,2646],{"class":265},"previousUser",[217,2648,2649],{"class":276},") ",[217,2651,270],{"class":269},[217,2653,2654,2657,2659,2661,2663,2665,2667,2669,2671,2673,2675,2677,2679,2681,2683,2685],{"class":219,"line":2219},[217,2655,2656],{"class":265},"        queryClient",[217,2658,897],{"class":269},[217,2660,2508],{"class":261},[217,2662,2475],{"class":276},[217,2664,287],{"class":286},[217,2666,476],{"class":227},[217,2668,287],{"class":286},[217,2670,295],{"class":269},[217,2672,1847],{"class":265},[217,2674,306],{"class":276},[217,2676,295],{"class":269},[217,2678,2619],{"class":265},[217,2680,897],{"class":269},[217,2682,2646],{"class":265},[217,2684,318],{"class":276},[217,2686,321],{"class":269},[217,2688,2689],{"class":219,"line":2228},[217,2690,2691],{"class":269},"      }\n",[217,2693,2695],{"class":219,"line":2694},33,[217,2696,1479],{"class":269},[217,2698,2700],{"class":219,"line":2699},34,[217,2701,432],{"emptyLinePlaceholder":431},[217,2703,2705,2708,2710,2712,2714,2716,2718,2720,2722,2724,2726,2728],{"class":219,"line":2704},35,[217,2706,2707],{"class":261},"    onSettled",[217,2709,280],{"class":269},[217,2711,1613],{"class":269},[217,2713,1943],{"class":695},[217,2715,295],{"class":269},[217,2717,561],{"class":695},[217,2719,295],{"class":269},[217,2721,408],{"class":269},[217,2723,1847],{"class":695},[217,2725,1876],{"class":269},[217,2727,496],{"class":439},[217,2729,449],{"class":269},[217,2731,2733],{"class":219,"line":2732},36,[217,2734,2735],{"class":247},"      \u002F\u002F 無論成功或失敗，最後都重新查詢確保資料正確\n",[217,2737,2739,2741,2743,2745,2747,2749,2751,2753,2755,2757,2759,2761,2763,2765,2767,2769,2771],{"class":219,"line":2738},37,[217,2740,1698],{"class":265},[217,2742,897],{"class":269},[217,2744,1703],{"class":261},[217,2746,266],{"class":276},[217,2748,1708],{"class":269},[217,2750,1711],{"class":276},[217,2752,280],{"class":269},[217,2754,283],{"class":276},[217,2756,287],{"class":286},[217,2758,476],{"class":227},[217,2760,287],{"class":286},[217,2762,295],{"class":269},[217,2764,1847],{"class":265},[217,2766,1724],{"class":276},[217,2768,315],{"class":269},[217,2770,318],{"class":276},[217,2772,321],{"class":269},[217,2774,2776],{"class":219,"line":2775},38,[217,2777,1479],{"class":269},[217,2779,2781,2783,2785],{"class":219,"line":2780},39,[217,2782,518],{"class":269},[217,2784,318],{"class":276},[217,2786,321],{"class":269},[217,2788,2790],{"class":219,"line":2789},40,[217,2791,528],{"class":269},[45,2793,2794],{"id":2794},"樂觀更新流程圖",[207,2796,2799],{"className":2797,"code":2798,"language":332},[330],"使用者點擊儲存\n       │\n       ▼\n┌──────────────────┐\n│  onMutate        │\n│  ├─ 取消進行中查詢 │\n│  ├─ 保存舊資料    │\n│  └─ 樂觀更新 UI   │ ← 立即顯示新值\n└──────────────────┘\n       │\n       ▼ 發送 API 請求\n       │\n   ┌───┴───┐\n   │       │\n成功 ▼     ▼ 失敗\n   │       │\n   │  ┌────┴────┐\n   │  │ onError │\n   │  │ 回滾資料 │ ← 恢復舊值\n   │  └─────────┘\n   │       │\n   └───┬───┘\n       │\n       ▼\n┌──────────────────┐\n│  onSettled       │\n│  重新查詢確保正確  │\n└──────────────────┘\n",[214,2800,2798],{"__ignoreMap":212},[38,2802],{},[11,2804,2805],{"id":2805},"快取策略",[45,2807,2809],{"id":2808},"staletime-vs-gctime","staleTime vs gcTime",[207,2811,2813],{"className":238,"code":2812,"language":240,"meta":212,"style":212},"useQuery({\n  key: [\"users\"],\n  query: () => $fetch(\"\u002Fapi\u002Fv1\u002Fusers\"),\n  staleTime: 5 * 60 * 1000, \u002F\u002F 5 分鐘內視為新鮮，不會重新請求\n  gcTime: 10 * 60 * 1000, \u002F\u002F 10 分鐘後從記憶體清除\n});\n",[214,2814,2815,2824,2843,2868,2891,2913],{"__ignoreMap":212},[217,2816,2817,2820,2822],{"class":219,"line":220},[217,2818,2819],{"class":261},"useQuery",[217,2821,266],{"class":265},[217,2823,270],{"class":269},[217,2825,2826,2829,2831,2833,2835,2837,2839,2841],{"class":219,"line":251},[217,2827,2828],{"class":276},"  key",[217,2830,280],{"class":269},[217,2832,283],{"class":265},[217,2834,287],{"class":286},[217,2836,476],{"class":227},[217,2838,287],{"class":286},[217,2840,306],{"class":265},[217,2842,309],{"class":269},[217,2844,2845,2848,2850,2852,2854,2856,2858,2860,2862,2864,2866],{"class":219,"line":273},[217,2846,2847],{"class":261},"  query",[217,2849,280],{"class":269},[217,2851,493],{"class":269},[217,2853,496],{"class":439},[217,2855,499],{"class":261},[217,2857,266],{"class":265},[217,2859,287],{"class":286},[217,2861,506],{"class":227},[217,2863,287],{"class":286},[217,2865,318],{"class":265},[217,2867,309],{"class":269},[217,2869,2870,2873,2875,2878,2880,2882,2884,2886,2888],{"class":219,"line":312},[217,2871,2872],{"class":276},"  staleTime",[217,2874,280],{"class":269},[217,2876,2877],{"class":1489}," 5",[217,2879,1493],{"class":571},[217,2881,1496],{"class":1489},[217,2883,1493],{"class":571},[217,2885,1501],{"class":1489},[217,2887,295],{"class":269},[217,2889,2890],{"class":247}," \u002F\u002F 5 分鐘內視為新鮮，不會重新請求\n",[217,2892,2893,2896,2898,2900,2902,2904,2906,2908,2910],{"class":219,"line":452},[217,2894,2895],{"class":276},"  gcTime",[217,2897,280],{"class":269},[217,2899,1490],{"class":1489},[217,2901,1493],{"class":571},[217,2903,1496],{"class":1489},[217,2905,1493],{"class":571},[217,2907,1501],{"class":1489},[217,2909,295],{"class":269},[217,2911,2912],{"class":247}," \u002F\u002F 10 分鐘後從記憶體清除\n",[217,2914,2915,2917,2919],{"class":219,"line":464},[217,2916,315],{"class":269},[217,2918,318],{"class":265},[217,2920,321],{"class":269},[50,2922,2923,2935],{},[53,2924,2925],{},[56,2926,2927,2930,2932],{},[59,2928,2929],{},"參數",[59,2931,596],{},[59,2933,2934],{},"建議值",[69,2936,2937,2950],{},[56,2938,2939,2944,2947],{},[74,2940,2941],{},[214,2942,2943],{},"staleTime",[74,2945,2946],{},"資料多久後視為過期",[74,2948,2949],{},"依資料變動頻率設定",[56,2951,2952,2957,2960],{},[74,2953,2954],{},[214,2955,2956],{},"gcTime",[74,2958,2959],{},"快取保留多久後清除",[74,2961,2962],{},"通常設為 staleTime 的 2 倍",[45,2964,2965],{"id":2965},"不同資料的快取策略",[207,2967,2969],{"className":238,"code":2968,"language":240,"meta":212,"style":212},"\u002F\u002F 變動頻繁的資料（如儀表板）\nuseQuery({\n  key: [\"dashboard\"],\n  query: () => $fetch(\"\u002Fapi\u002Fv1\u002Fdashboard\"),\n  staleTime: 30 * 1000, \u002F\u002F 30 秒\n  refetchInterval: 60 * 1000, \u002F\u002F 每分鐘自動重新查詢\n});\n\n\u002F\u002F 較少變動的資料（如下拉選項）\nuseQuery({\n  key: [\"options\", \"categories\"],\n  query: () => $fetch(\"\u002Fapi\u002Fv1\u002Fcategories\"),\n  staleTime: 30 * 60 * 1000, \u002F\u002F 30 分鐘\n});\n\n\u002F\u002F 幾乎不變的資料（如設定）\nuseQuery({\n  key: [\"config\"],\n  query: () => $fetch(\"\u002Fapi\u002Fv1\u002Fconfig\"),\n  staleTime: Infinity, \u002F\u002F 永不過期\n});\n",[214,2970,2971,2976,2984,3003,3028,3046,3064,3072,3076,3081,3089,3116,3141,3162,3170,3174,3179,3187,3206,3231,3246],{"__ignoreMap":212},[217,2972,2973],{"class":219,"line":220},[217,2974,2975],{"class":247},"\u002F\u002F 變動頻繁的資料（如儀表板）\n",[217,2977,2978,2980,2982],{"class":219,"line":251},[217,2979,2819],{"class":261},[217,2981,266],{"class":265},[217,2983,270],{"class":269},[217,2985,2986,2988,2990,2992,2994,2997,2999,3001],{"class":219,"line":273},[217,2987,2828],{"class":276},[217,2989,280],{"class":269},[217,2991,283],{"class":265},[217,2993,287],{"class":286},[217,2995,2996],{"class":227},"dashboard",[217,2998,287],{"class":286},[217,3000,306],{"class":265},[217,3002,309],{"class":269},[217,3004,3005,3007,3009,3011,3013,3015,3017,3019,3022,3024,3026],{"class":219,"line":312},[217,3006,2847],{"class":261},[217,3008,280],{"class":269},[217,3010,493],{"class":269},[217,3012,496],{"class":439},[217,3014,499],{"class":261},[217,3016,266],{"class":265},[217,3018,287],{"class":286},[217,3020,3021],{"class":227},"\u002Fapi\u002Fv1\u002Fdashboard",[217,3023,287],{"class":286},[217,3025,318],{"class":265},[217,3027,309],{"class":269},[217,3029,3030,3032,3034,3037,3039,3041,3043],{"class":219,"line":452},[217,3031,2872],{"class":276},[217,3033,280],{"class":269},[217,3035,3036],{"class":1489}," 30",[217,3038,1493],{"class":571},[217,3040,1501],{"class":1489},[217,3042,295],{"class":269},[217,3044,3045],{"class":247}," \u002F\u002F 30 秒\n",[217,3047,3048,3051,3053,3055,3057,3059,3061],{"class":219,"line":464},[217,3049,3050],{"class":276},"  refetchInterval",[217,3052,280],{"class":269},[217,3054,1496],{"class":1489},[217,3056,1493],{"class":571},[217,3058,1501],{"class":1489},[217,3060,295],{"class":269},[217,3062,3063],{"class":247}," \u002F\u002F 每分鐘自動重新查詢\n",[217,3065,3066,3068,3070],{"class":219,"line":485},[217,3067,315],{"class":269},[217,3069,318],{"class":265},[217,3071,321],{"class":269},[217,3073,3074],{"class":219,"line":515},[217,3075,432],{"emptyLinePlaceholder":431},[217,3077,3078],{"class":219,"line":525},[217,3079,3080],{"class":247},"\u002F\u002F 較少變動的資料（如下拉選項）\n",[217,3082,3083,3085,3087],{"class":219,"line":531},[217,3084,2819],{"class":261},[217,3086,266],{"class":265},[217,3088,270],{"class":269},[217,3090,3091,3093,3095,3097,3099,3101,3103,3105,3107,3110,3112,3114],{"class":219,"line":536},[217,3092,2828],{"class":276},[217,3094,280],{"class":269},[217,3096,283],{"class":265},[217,3098,287],{"class":286},[217,3100,1328],{"class":227},[217,3102,287],{"class":286},[217,3104,295],{"class":269},[217,3106,298],{"class":286},[217,3108,3109],{"class":227},"categories",[217,3111,287],{"class":286},[217,3113,306],{"class":265},[217,3115,309],{"class":269},[217,3117,3118,3120,3122,3124,3126,3128,3130,3132,3135,3137,3139],{"class":219,"line":542},[217,3119,2847],{"class":261},[217,3121,280],{"class":269},[217,3123,493],{"class":269},[217,3125,496],{"class":439},[217,3127,499],{"class":261},[217,3129,266],{"class":265},[217,3131,287],{"class":286},[217,3133,3134],{"class":227},"\u002Fapi\u002Fv1\u002Fcategories",[217,3136,287],{"class":286},[217,3138,318],{"class":265},[217,3140,309],{"class":269},[217,3142,3143,3145,3147,3149,3151,3153,3155,3157,3159],{"class":219,"line":886},[217,3144,2872],{"class":276},[217,3146,280],{"class":269},[217,3148,3036],{"class":1489},[217,3150,1493],{"class":571},[217,3152,1496],{"class":1489},[217,3154,1493],{"class":571},[217,3156,1501],{"class":1489},[217,3158,295],{"class":269},[217,3160,3161],{"class":247}," \u002F\u002F 30 分鐘\n",[217,3163,3164,3166,3168],{"class":219,"line":892},[217,3165,315],{"class":269},[217,3167,318],{"class":265},[217,3169,321],{"class":269},[217,3171,3172],{"class":219,"line":1140},[217,3173,432],{"emptyLinePlaceholder":431},[217,3175,3176],{"class":219,"line":1148},[217,3177,3178],{"class":247},"\u002F\u002F 幾乎不變的資料（如設定）\n",[217,3180,3181,3183,3185],{"class":219,"line":1160},[217,3182,2819],{"class":261},[217,3184,266],{"class":265},[217,3186,270],{"class":269},[217,3188,3189,3191,3193,3195,3197,3200,3202,3204],{"class":219,"line":1178},[217,3190,2828],{"class":276},[217,3192,280],{"class":269},[217,3194,283],{"class":265},[217,3196,287],{"class":286},[217,3198,3199],{"class":227},"config",[217,3201,287],{"class":286},[217,3203,306],{"class":265},[217,3205,309],{"class":269},[217,3207,3208,3210,3212,3214,3216,3218,3220,3222,3225,3227,3229],{"class":219,"line":1188},[217,3209,2847],{"class":261},[217,3211,280],{"class":269},[217,3213,493],{"class":269},[217,3215,496],{"class":439},[217,3217,499],{"class":261},[217,3219,266],{"class":265},[217,3221,287],{"class":286},[217,3223,3224],{"class":227},"\u002Fapi\u002Fv1\u002Fconfig",[217,3226,287],{"class":286},[217,3228,318],{"class":265},[217,3230,309],{"class":269},[217,3232,3233,3235,3237,3241,3243],{"class":219,"line":1210},[217,3234,2872],{"class":276},[217,3236,280],{"class":269},[217,3238,3240],{"class":3239},"s39Yj"," Infinity",[217,3242,295],{"class":269},[217,3244,3245],{"class":247}," \u002F\u002F 永不過期\n",[217,3247,3248,3250,3252],{"class":219,"line":1232},[217,3249,315],{"class":269},[217,3251,318],{"class":265},[217,3253,321],{"class":269},[38,3255],{},[11,3257,3258],{"id":3258},"手動控制快取",[45,3260,3261],{"id":3261},"使快取失效",[207,3263,3265],{"className":238,"code":3264,"language":240,"meta":212,"style":212},"const queryClient = useQueryClient();\n\n\u002F\u002F 使特定查詢失效\nqueryClient.invalidateQueries({ key: [\"users\", \"123\"] });\n\n\u002F\u002F 使所有 users 相關查詢失效\nqueryClient.invalidateQueries({ key: [\"users\"] });\n\n\u002F\u002F 使所有查詢失效\nqueryClient.invalidateQueries();\n",[214,3266,3267,3281,3285,3290,3331,3335,3340,3372,3376,3381],{"__ignoreMap":212},[217,3268,3269,3271,3273,3275,3277,3279],{"class":219,"line":220},[217,3270,545],{"class":439},[217,3272,1581],{"class":550},[217,3274,572],{"class":571},[217,3276,1544],{"class":261},[217,3278,446],{"class":265},[217,3280,321],{"class":269},[217,3282,3283],{"class":219,"line":251},[217,3284,432],{"emptyLinePlaceholder":431},[217,3286,3287],{"class":219,"line":273},[217,3288,3289],{"class":247},"\u002F\u002F 使特定查詢失效\n",[217,3291,3292,3295,3297,3299,3301,3303,3305,3307,3309,3311,3313,3315,3317,3319,3321,3323,3325,3327,3329],{"class":219,"line":312},[217,3293,3294],{"class":265},"queryClient",[217,3296,897],{"class":269},[217,3298,1703],{"class":261},[217,3300,266],{"class":265},[217,3302,1708],{"class":269},[217,3304,1711],{"class":276},[217,3306,280],{"class":269},[217,3308,283],{"class":265},[217,3310,287],{"class":286},[217,3312,476],{"class":227},[217,3314,287],{"class":286},[217,3316,295],{"class":269},[217,3318,298],{"class":286},[217,3320,852],{"class":227},[217,3322,287],{"class":286},[217,3324,1724],{"class":265},[217,3326,315],{"class":269},[217,3328,318],{"class":265},[217,3330,321],{"class":269},[217,3332,3333],{"class":219,"line":452},[217,3334,432],{"emptyLinePlaceholder":431},[217,3336,3337],{"class":219,"line":464},[217,3338,3339],{"class":247},"\u002F\u002F 使所有 users 相關查詢失效\n",[217,3341,3342,3344,3346,3348,3350,3352,3354,3356,3358,3360,3362,3364,3366,3368,3370],{"class":219,"line":485},[217,3343,3294],{"class":265},[217,3345,897],{"class":269},[217,3347,1703],{"class":261},[217,3349,266],{"class":265},[217,3351,1708],{"class":269},[217,3353,1711],{"class":276},[217,3355,280],{"class":269},[217,3357,283],{"class":265},[217,3359,287],{"class":286},[217,3361,476],{"class":227},[217,3363,287],{"class":286},[217,3365,1724],{"class":265},[217,3367,315],{"class":269},[217,3369,318],{"class":265},[217,3371,321],{"class":269},[217,3373,3374],{"class":219,"line":515},[217,3375,432],{"emptyLinePlaceholder":431},[217,3377,3378],{"class":219,"line":525},[217,3379,3380],{"class":247},"\u002F\u002F 使所有查詢失效\n",[217,3382,3383,3385,3387,3389,3391],{"class":219,"line":531},[217,3384,3294],{"class":265},[217,3386,897],{"class":269},[217,3388,1703],{"class":261},[217,3390,446],{"class":265},[217,3392,321],{"class":269},[45,3394,3395],{"id":3395},"直接設定快取資料",[207,3397,3399],{"className":238,"code":3398,"language":240,"meta":212,"style":212},"\u002F\u002F 設定快取資料（不觸發重新查詢）\nqueryClient.setQueryData([\"users\", \"123\"], newUserData);\n\n\u002F\u002F 取得快取資料\nconst cachedUser = queryClient.getQueryData([\"users\", \"123\"]);\n",[214,3400,3401,3406,3439,3443,3448],{"__ignoreMap":212},[217,3402,3403],{"class":219,"line":220},[217,3404,3405],{"class":247},"\u002F\u002F 設定快取資料（不觸發重新查詢）\n",[217,3407,3408,3410,3412,3414,3416,3418,3420,3422,3424,3426,3428,3430,3432,3434,3437],{"class":219,"line":251},[217,3409,3294],{"class":265},[217,3411,897],{"class":269},[217,3413,2508],{"class":261},[217,3415,2475],{"class":265},[217,3417,287],{"class":286},[217,3419,476],{"class":227},[217,3421,287],{"class":286},[217,3423,295],{"class":269},[217,3425,298],{"class":286},[217,3427,852],{"class":227},[217,3429,287],{"class":286},[217,3431,306],{"class":265},[217,3433,295],{"class":269},[217,3435,3436],{"class":265}," newUserData)",[217,3438,321],{"class":269},[217,3440,3441],{"class":219,"line":273},[217,3442,432],{"emptyLinePlaceholder":431},[217,3444,3445],{"class":219,"line":312},[217,3446,3447],{"class":247},"\u002F\u002F 取得快取資料\n",[217,3449,3450,3452,3455,3457,3459,3461,3463,3465,3467,3469,3471,3473,3475,3477,3479,3481],{"class":219,"line":452},[217,3451,545],{"class":439},[217,3453,3454],{"class":550}," cachedUser",[217,3456,572],{"class":571},[217,3458,1581],{"class":265},[217,3460,897],{"class":269},[217,3462,2472],{"class":261},[217,3464,2475],{"class":265},[217,3466,287],{"class":286},[217,3468,476],{"class":227},[217,3470,287],{"class":286},[217,3472,295],{"class":269},[217,3474,298],{"class":286},[217,3476,852],{"class":227},[217,3478,287],{"class":286},[217,3480,2488],{"class":265},[217,3482,321],{"class":269},[38,3484],{},[11,3486,3488],{"id":3487},"與-pinia-store-搭配","與 Pinia Store 搭配",[45,3490,3492],{"id":3491},"store-管理-client-狀態","Store 管理 Client 狀態",[207,3494,3496],{"className":238,"code":3495,"language":240,"meta":212,"style":212},"\u002F\u002F app\u002Fstores\u002FuserPreferences.ts\nexport const useUserPreferencesStore = defineStore(\"user-preferences\", () => {\n  const primaryColor = ref(\"blue\");\n  const sidebarCollapsed = ref(false);\n\n  function setPrimaryColor(color: string) {\n    primaryColor.value = color;\n  }\n\n  return {\n    primaryColor: readonly(primaryColor),\n    sidebarCollapsed,\n    setPrimaryColor,\n  };\n});\n",[214,3497,3498,3503,3535,3559,3580,3584,3605,3622,3627,3631,3637,3655,3662,3669,3674],{"__ignoreMap":212},[217,3499,3500],{"class":219,"line":220},[217,3501,3502],{"class":247},"\u002F\u002F app\u002Fstores\u002FuserPreferences.ts\n",[217,3504,3505,3507,3510,3513,3515,3518,3520,3522,3525,3527,3529,3531,3533],{"class":219,"line":251},[217,3506,255],{"class":254},[217,3508,3509],{"class":439}," const",[217,3511,3512],{"class":550}," useUserPreferencesStore",[217,3514,572],{"class":571},[217,3516,3517],{"class":261}," defineStore",[217,3519,266],{"class":265},[217,3521,287],{"class":286},[217,3523,3524],{"class":227},"user-preferences",[217,3526,287],{"class":286},[217,3528,295],{"class":269},[217,3530,493],{"class":269},[217,3532,496],{"class":439},[217,3534,449],{"class":269},[217,3536,3537,3539,3542,3544,3546,3548,3550,3553,3555,3557],{"class":219,"line":273},[217,3538,1578],{"class":439},[217,3540,3541],{"class":550}," primaryColor",[217,3543,572],{"class":571},[217,3545,845],{"class":261},[217,3547,266],{"class":276},[217,3549,287],{"class":286},[217,3551,3552],{"class":227},"blue",[217,3554,287],{"class":286},[217,3556,318],{"class":276},[217,3558,321],{"class":269},[217,3560,3561,3563,3566,3568,3570,3572,3576,3578],{"class":219,"line":312},[217,3562,1578],{"class":439},[217,3564,3565],{"class":550}," sidebarCollapsed",[217,3567,572],{"class":571},[217,3569,845],{"class":261},[217,3571,266],{"class":276},[217,3573,3575],{"class":3574},"syTEX","false",[217,3577,318],{"class":276},[217,3579,321],{"class":269},[217,3581,3582],{"class":219,"line":452},[217,3583,432],{"emptyLinePlaceholder":431},[217,3585,3586,3589,3592,3594,3597,3599,3601,3603],{"class":219,"line":464},[217,3587,3588],{"class":439},"  function",[217,3590,3591],{"class":261}," setPrimaryColor",[217,3593,266],{"class":269},[217,3595,3596],{"class":695},"color",[217,3598,280],{"class":571},[217,3600,1864],{"class":713},[217,3602,318],{"class":269},[217,3604,449],{"class":269},[217,3606,3607,3610,3612,3615,3617,3620],{"class":219,"line":485},[217,3608,3609],{"class":265},"    primaryColor",[217,3611,897],{"class":269},[217,3613,3614],{"class":265},"value",[217,3616,572],{"class":571},[217,3618,3619],{"class":265}," color",[217,3621,321],{"class":269},[217,3623,3624],{"class":219,"line":515},[217,3625,3626],{"class":269},"  }\n",[217,3628,3629],{"class":219,"line":525},[217,3630,432],{"emptyLinePlaceholder":431},[217,3632,3633,3635],{"class":219,"line":531},[217,3634,455],{"class":254},[217,3636,449],{"class":269},[217,3638,3639,3641,3643,3646,3648,3651,3653],{"class":219,"line":536},[217,3640,3609],{"class":276},[217,3642,280],{"class":269},[217,3644,3645],{"class":261}," readonly",[217,3647,266],{"class":276},[217,3649,3650],{"class":265},"primaryColor",[217,3652,318],{"class":276},[217,3654,309],{"class":269},[217,3656,3657,3660],{"class":219,"line":542},[217,3658,3659],{"class":265},"    sidebarCollapsed",[217,3661,309],{"class":269},[217,3663,3664,3667],{"class":219,"line":886},[217,3665,3666],{"class":265},"    setPrimaryColor",[217,3668,309],{"class":269},[217,3670,3671],{"class":219,"line":892},[217,3672,3673],{"class":269},"  };\n",[217,3675,3676,3678,3680],{"class":219,"line":1140},[217,3677,315],{"class":269},[217,3679,318],{"class":265},[217,3681,321],{"class":269},[45,3683,3685],{"id":3684},"query-管理-server-資料","Query 管理 Server 資料",[207,3687,3689],{"className":238,"code":3688,"language":240,"meta":212,"style":212},"\u002F\u002F app\u002Fqueries\u002Fusers.ts\nexport function useCurrentUserQuery() {\n  const { user } = useUserSession();\n\n  return useQuery({\n    key: () => [\"users\", user.value?.id],\n    query: () => $fetch(`\u002Fapi\u002Fv1\u002Fusers\u002F${user.value?.id}`),\n    enabled: () => !!user.value?.id, \u002F\u002F 只在登入後查詢\n  });\n}\n",[214,3690,3691,3695,3708,3727,3731,3741,3775,3812,3841,3849],{"__ignoreMap":212},[217,3692,3693],{"class":219,"line":220},[217,3694,400],{"class":247},[217,3696,3697,3699,3701,3704,3706],{"class":219,"line":251},[217,3698,255],{"class":254},[217,3700,440],{"class":439},[217,3702,3703],{"class":261}," useCurrentUserQuery",[217,3705,446],{"class":269},[217,3707,449],{"class":269},[217,3709,3710,3712,3714,3716,3718,3720,3723,3725],{"class":219,"line":273},[217,3711,1578],{"class":439},[217,3713,408],{"class":269},[217,3715,870],{"class":550},[217,3717,414],{"class":269},[217,3719,572],{"class":571},[217,3721,3722],{"class":261}," useUserSession",[217,3724,446],{"class":276},[217,3726,321],{"class":269},[217,3728,3729],{"class":219,"line":312},[217,3730,432],{"emptyLinePlaceholder":431},[217,3732,3733,3735,3737,3739],{"class":219,"line":452},[217,3734,455],{"class":254},[217,3736,411],{"class":261},[217,3738,266],{"class":276},[217,3740,270],{"class":269},[217,3742,3743,3745,3747,3749,3751,3753,3755,3757,3759,3761,3763,3765,3767,3769,3771,3773],{"class":219,"line":464},[217,3744,467],{"class":261},[217,3746,280],{"class":269},[217,3748,493],{"class":269},[217,3750,496],{"class":439},[217,3752,283],{"class":276},[217,3754,287],{"class":286},[217,3756,476],{"class":227},[217,3758,287],{"class":286},[217,3760,295],{"class":269},[217,3762,870],{"class":265},[217,3764,897],{"class":269},[217,3766,3614],{"class":265},[217,3768,2643],{"class":269},[217,3770,1893],{"class":265},[217,3772,306],{"class":276},[217,3774,309],{"class":269},[217,3776,3777,3779,3781,3783,3785,3787,3789,3791,3793,3795,3798,3800,3802,3804,3806,3808,3810],{"class":219,"line":485},[217,3778,488],{"class":261},[217,3780,280],{"class":269},[217,3782,493],{"class":269},[217,3784,496],{"class":439},[217,3786,499],{"class":261},[217,3788,266],{"class":276},[217,3790,785],{"class":286},[217,3792,788],{"class":227},[217,3794,791],{"class":286},[217,3796,3797],{"class":265},"user",[217,3799,897],{"class":286},[217,3801,3614],{"class":265},[217,3803,2643],{"class":286},[217,3805,1893],{"class":265},[217,3807,804],{"class":286},[217,3809,318],{"class":276},[217,3811,309],{"class":269},[217,3813,3814,3817,3819,3821,3823,3826,3828,3830,3832,3834,3836,3838],{"class":219,"line":515},[217,3815,3816],{"class":261},"    enabled",[217,3818,280],{"class":269},[217,3820,493],{"class":269},[217,3822,496],{"class":439},[217,3824,3825],{"class":571}," !!",[217,3827,3797],{"class":265},[217,3829,897],{"class":269},[217,3831,3614],{"class":265},[217,3833,2643],{"class":269},[217,3835,1893],{"class":265},[217,3837,295],{"class":269},[217,3839,3840],{"class":247}," \u002F\u002F 只在登入後查詢\n",[217,3842,3843,3845,3847],{"class":219,"line":525},[217,3844,518],{"class":269},[217,3846,318],{"class":276},[217,3848,321],{"class":269},[217,3850,3851],{"class":219,"line":531},[217,3852,528],{"class":269},[45,3854,3855],{"id":3855},"組合使用",[207,3857,3859],{"className":1752,"code":3858,"language":1754,"meta":212,"style":212},"&lt;script setup lang=\"ts\"&gt; \u002F\u002F Client 狀態用 Store const preferencesStore =\nuseUserPreferencesStore() const { primaryColor } = storeToRefs(preferencesStore)\n\u002F\u002F Server 資料用 Query const { data: user, isLoading } = useCurrentUserQuery()\n&lt;\u002Fscript&gt;\n",[214,3860,3861,3866,3871,3876],{"__ignoreMap":212},[217,3862,3863],{"class":219,"line":220},[217,3864,3865],{"class":265},"&lt;script setup lang=\"ts\"&gt; \u002F\u002F Client 狀態用 Store const preferencesStore =\n",[217,3867,3868],{"class":219,"line":251},[217,3869,3870],{"class":265},"useUserPreferencesStore() const { primaryColor } = storeToRefs(preferencesStore)\n",[217,3872,3873],{"class":219,"line":273},[217,3874,3875],{"class":265},"\u002F\u002F Server 資料用 Query const { data: user, isLoading } = useCurrentUserQuery()\n",[217,3877,3878],{"class":219,"line":312},[217,3879,3880],{"class":265},"&lt;\u002Fscript&gt;\n",[38,3882],{},[11,3884,3885],{"id":3885},"踩坑經驗",[45,3887,3889],{"id":3888},"快取-key-設計錯誤","快取 Key 設計錯誤",[15,3891,3892,3896],{},[3893,3894,3895],"strong",{},"問題","：mutation 後 invalidate 沒有清除對應的快取。",[207,3898,3900],{"className":238,"code":3899,"language":240,"meta":212,"style":212},"\u002F\u002F ❌ 錯誤：key 不一致\n\u002F\u002F query\nuseQuery({ key: [\"user\", userId] });\n\n\u002F\u002F mutation invalidate\nqueryClient.invalidateQueries({ key: [\"users\", userId] }); \u002F\u002F users vs user\n",[214,3901,3902,3907,3912,3943,3947,3952],{"__ignoreMap":212},[217,3903,3904],{"class":219,"line":220},[217,3905,3906],{"class":247},"\u002F\u002F ❌ 錯誤：key 不一致\n",[217,3908,3909],{"class":219,"line":251},[217,3910,3911],{"class":247},"\u002F\u002F query\n",[217,3913,3914,3916,3918,3920,3922,3924,3926,3928,3930,3932,3934,3937,3939,3941],{"class":219,"line":273},[217,3915,2819],{"class":261},[217,3917,266],{"class":265},[217,3919,1708],{"class":269},[217,3921,1711],{"class":276},[217,3923,280],{"class":269},[217,3925,283],{"class":265},[217,3927,287],{"class":286},[217,3929,3797],{"class":227},[217,3931,287],{"class":286},[217,3933,295],{"class":269},[217,3935,3936],{"class":265}," userId] ",[217,3938,315],{"class":269},[217,3940,318],{"class":265},[217,3942,321],{"class":269},[217,3944,3945],{"class":219,"line":312},[217,3946,432],{"emptyLinePlaceholder":431},[217,3948,3949],{"class":219,"line":452},[217,3950,3951],{"class":247},"\u002F\u002F mutation invalidate\n",[217,3953,3954,3956,3958,3960,3962,3964,3966,3968,3970,3972,3974,3976,3978,3980,3982,3984,3986],{"class":219,"line":464},[217,3955,3294],{"class":265},[217,3957,897],{"class":269},[217,3959,1703],{"class":261},[217,3961,266],{"class":265},[217,3963,1708],{"class":269},[217,3965,1711],{"class":276},[217,3967,280],{"class":269},[217,3969,283],{"class":265},[217,3971,287],{"class":286},[217,3973,476],{"class":227},[217,3975,287],{"class":286},[217,3977,295],{"class":269},[217,3979,3936],{"class":265},[217,3981,315],{"class":269},[217,3983,318],{"class":265},[217,3985,710],{"class":269},[217,3987,3988],{"class":247}," \u002F\u002F users vs user\n",[15,3990,3991,3994],{},[3893,3992,3993],{},"解決","：統一 key 命名規則。",[207,3996,3998],{"className":238,"code":3997,"language":240,"meta":212,"style":212},"\u002F\u002F ✅ 正確：使用一致的命名\n\u002F\u002F 單筆：['users', id]\n\u002F\u002F 列表：['users', 'list', params]\n\u002F\u002F 選項：['users', 'options']\n",[214,3999,4000,4005,4010,4015],{"__ignoreMap":212},[217,4001,4002],{"class":219,"line":220},[217,4003,4004],{"class":247},"\u002F\u002F ✅ 正確：使用一致的命名\n",[217,4006,4007],{"class":219,"line":251},[217,4008,4009],{"class":247},"\u002F\u002F 單筆：['users', id]\n",[217,4011,4012],{"class":219,"line":273},[217,4013,4014],{"class":247},"\u002F\u002F 列表：['users', 'list', params]\n",[217,4016,4017],{"class":219,"line":312},[217,4018,4019],{"class":247},"\u002F\u002F 選項：['users', 'options']\n",[45,4021,4023],{"id":4022},"忘記處理-enabled-條件","忘記處理 enabled 條件",[15,4025,4026,4028],{},[3893,4027,3895],{},"：userId 為 undefined 時仍然發送請求。",[207,4030,4032],{"className":238,"code":4031,"language":240,"meta":212,"style":212},"\u002F\u002F ❌ 錯誤：會發送 \u002Fapi\u002Fv1\u002Fusers\u002Fundefined\nuseQuery({\n  key: () => [\"users\", toValue(userId)],\n  query: () => $fetch(`\u002Fapi\u002Fv1\u002Fusers\u002F${toValue(userId)}`),\n});\n",[214,4033,4034,4039,4047,4074,4108],{"__ignoreMap":212},[217,4035,4036],{"class":219,"line":220},[217,4037,4038],{"class":247},"\u002F\u002F ❌ 錯誤：會發送 \u002Fapi\u002Fv1\u002Fusers\u002Fundefined\n",[217,4040,4041,4043,4045],{"class":219,"line":251},[217,4042,2819],{"class":261},[217,4044,266],{"class":265},[217,4046,270],{"class":269},[217,4048,4049,4051,4053,4055,4057,4059,4061,4063,4065,4067,4069,4072],{"class":219,"line":273},[217,4050,2828],{"class":261},[217,4052,280],{"class":269},[217,4054,493],{"class":269},[217,4056,496],{"class":439},[217,4058,283],{"class":265},[217,4060,287],{"class":286},[217,4062,476],{"class":227},[217,4064,287],{"class":286},[217,4066,295],{"class":269},[217,4068,759],{"class":261},[217,4070,4071],{"class":265},"(userId)]",[217,4073,309],{"class":269},[217,4075,4076,4078,4080,4082,4084,4086,4088,4090,4092,4094,4096,4098,4100,4102,4104,4106],{"class":219,"line":312},[217,4077,2847],{"class":261},[217,4079,280],{"class":269},[217,4081,493],{"class":269},[217,4083,496],{"class":439},[217,4085,499],{"class":261},[217,4087,266],{"class":265},[217,4089,785],{"class":286},[217,4091,788],{"class":227},[217,4093,791],{"class":286},[217,4095,794],{"class":261},[217,4097,266],{"class":797},[217,4099,696],{"class":265},[217,4101,318],{"class":797},[217,4103,804],{"class":286},[217,4105,318],{"class":265},[217,4107,309],{"class":269},[217,4109,4110,4112,4114],{"class":219,"line":452},[217,4111,315],{"class":269},[217,4113,318],{"class":265},[217,4115,321],{"class":269},[15,4117,4118,4120],{},[3893,4119,3993],{},"：加上 enabled 條件。",[207,4122,4124],{"className":238,"code":4123,"language":240,"meta":212,"style":212},"\u002F\u002F ✅ 正確：userId 存在才查詢\nuseQuery({\n  key: () => [\"users\", toValue(userId)],\n  query: () => $fetch(`\u002Fapi\u002Fv1\u002Fusers\u002F${toValue(userId)}`),\n  enabled: () => !!toValue(userId),\n});\n",[214,4125,4126,4131,4139,4165,4199,4219],{"__ignoreMap":212},[217,4127,4128],{"class":219,"line":220},[217,4129,4130],{"class":247},"\u002F\u002F ✅ 正確：userId 存在才查詢\n",[217,4132,4133,4135,4137],{"class":219,"line":251},[217,4134,2819],{"class":261},[217,4136,266],{"class":265},[217,4138,270],{"class":269},[217,4140,4141,4143,4145,4147,4149,4151,4153,4155,4157,4159,4161,4163],{"class":219,"line":273},[217,4142,2828],{"class":261},[217,4144,280],{"class":269},[217,4146,493],{"class":269},[217,4148,496],{"class":439},[217,4150,283],{"class":265},[217,4152,287],{"class":286},[217,4154,476],{"class":227},[217,4156,287],{"class":286},[217,4158,295],{"class":269},[217,4160,759],{"class":261},[217,4162,4071],{"class":265},[217,4164,309],{"class":269},[217,4166,4167,4169,4171,4173,4175,4177,4179,4181,4183,4185,4187,4189,4191,4193,4195,4197],{"class":219,"line":312},[217,4168,2847],{"class":261},[217,4170,280],{"class":269},[217,4172,493],{"class":269},[217,4174,496],{"class":439},[217,4176,499],{"class":261},[217,4178,266],{"class":265},[217,4180,785],{"class":286},[217,4182,788],{"class":227},[217,4184,791],{"class":286},[217,4186,794],{"class":261},[217,4188,266],{"class":797},[217,4190,696],{"class":265},[217,4192,318],{"class":797},[217,4194,804],{"class":286},[217,4196,318],{"class":265},[217,4198,309],{"class":269},[217,4200,4201,4204,4206,4208,4210,4212,4214,4217],{"class":219,"line":452},[217,4202,4203],{"class":261},"  enabled",[217,4205,280],{"class":269},[217,4207,493],{"class":269},[217,4209,496],{"class":439},[217,4211,3825],{"class":571},[217,4213,794],{"class":261},[217,4215,4216],{"class":265},"(userId)",[217,4218,309],{"class":269},[217,4220,4221,4223,4225],{"class":219,"line":464},[217,4222,315],{"class":269},[217,4224,318],{"class":265},[217,4226,321],{"class":269},[45,4228,4229],{"id":4229},"樂觀更新沒有回滾",[15,4231,4232,4234],{},[3893,4233,3895],{},"：API 失敗但 UI 仍顯示錯誤的值。",[15,4236,4237,4239],{},[3893,4238,3993],{},"：確保 onError 中有回滾邏輯，並在 onSettled 中重新查詢。",[38,4241],{},[11,4243,4244],{"id":4244},"檢查清單",[15,4246,4247],{},"建立新 Query\u002FMutation 時確認：",[19,4249,4252,4269,4279,4289,4298,4314],{"className":4250},[4251],"contains-task-list",[22,4253,4256,4260,4261,4264,4265,4268],{"className":4254},[4255],"task-list-item",[4257,4258],"input",{"disabled":431,"type":4259},"checkbox"," Key 設計一致（單筆 ",[214,4262,4263],{},"['resource', id]","、列表 ",[214,4266,4267],{},"['resource', 'list']","）",[22,4270,4272,4274,4275,4278],{"className":4271},[4255],[4257,4273],{"disabled":431,"type":4259}," 需要參數的查詢使用 ",[214,4276,4277],{},"MaybeRefOrGetter"," 類型",[22,4280,4282,4284,4285,4288],{"className":4281},[4255],[4257,4283],{"disabled":431,"type":4259}," 條件查詢加上 ",[214,4286,4287],{},"enabled"," 選項",[22,4290,4292,4294,4295,4297],{"className":4291},[4255],[4257,4293],{"disabled":431,"type":4259}," Mutation 成功後 ",[214,4296,1703],{}," 清除相關快取",[22,4299,4301,4303,4304,4307,4308,4307,4311],{"className":4300},[4255],[4257,4302],{"disabled":431,"type":4259}," 需要樂觀更新時實作 ",[214,4305,4306],{},"onMutate"," + ",[214,4309,4310],{},"onError",[214,4312,4313],{},"onSettled",[22,4315,4317,4319,4320],{"className":4316},[4255],[4257,4318],{"disabled":431,"type":4259}," 依資料特性設定適當的 ",[214,4321,2943],{},[38,4323],{},[11,4325,4326],{"id":4326},"最佳實踐總結",[4328,4329,4330,4336,4348,4356,4361,4370],"ol",{},[22,4331,4332,4335],{},[3893,4333,4334],{},"分離關注點","：Query 管理 Server 資料，Store 管理 Client 狀態",[22,4337,4338,4341,4342,4344,4345],{},[3893,4339,4340],{},"統一 Key 設計","：",[214,4343,4263],{}," 或 ",[214,4346,4347],{},"['resource', 'list', params]",[22,4349,4350,4353,4354],{},[3893,4351,4352],{},"合理的快取時間","：依資料變動頻率設定 ",[214,4355,2943],{},[22,4357,4358,4360],{},[3893,4359,193],{},"：提升 UX，但要完整處理回滾",[22,4362,4363,4366,4367,4369],{},[3893,4364,4365],{},"條件查詢","：使用 ",[214,4368,4287],{}," 避免無效請求",[22,4371,4372,4375,4376,4379],{},[3893,4373,4374],{},"集中管理","：Query 函式放在 ",[214,4377,4378],{},"app\u002Fqueries\u002F"," 目錄",[38,4381],{},[11,4383,4384],{"id":4384},"延伸閱讀",[19,4386,4387,4396,4403,4410],{},[22,4388,4389],{},[4390,4391,4395],"a",{"href":4392,"rel":4393},"https:\u002F\u002Fpinia-colada.esm.dev\u002F",[4394],"nofollow","Pinia Colada 文件",[22,4397,4398],{},[4390,4399,4402],{"href":4400,"rel":4401},"https:\u002F\u002Fpinia.vuejs.org\u002F",[4394],"Pinia 官方文檔",[22,4404,4405,4406],{},"上一篇：",[4390,4407,4409],{"href":4408},"\u002Fblog\u002Fnuxt\u002Fnitro-api-design","Nitro Server API 設計模式",[22,4411,4412,4413],{},"下一篇：",[4390,4414,4416],{"href":4415},"\u002Fblog\u002Fnuxt\u002Ftdd-testing-workflow","TDD 與自動化測試",[4418,4419,4420],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sfo-9, html code.shiki .sfo-9{--shiki-light:#90A4AE;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sucvu, html code.shiki .sucvu{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":212,"searchDepth":273,"depth":273,"links":4422},[4423,4424,4428,4432,4435,4442,4447,4451,4455,4459,4464,4469,4470,4471],{"id":13,"depth":251,"text":13},{"id":42,"depth":251,"text":43,"children":4425},[4426,4427],{"id":47,"depth":273,"text":48},{"id":140,"depth":273,"text":141},{"id":202,"depth":251,"text":202,"children":4429},[4430,4431],{"id":205,"depth":273,"text":205},{"id":234,"depth":273,"text":235},{"id":326,"depth":251,"text":326,"children":4433},[4434],{"id":337,"depth":273,"text":338},{"id":386,"depth":251,"text":387,"children":4436},[4437,4438,4439,4440,4441],{"id":390,"depth":273,"text":390},{"id":581,"depth":273,"text":581},{"id":676,"depth":273,"text":676},{"id":915,"depth":273,"text":915},{"id":1282,"depth":273,"text":1282},{"id":1521,"depth":251,"text":1522,"children":4443},[4444,4445,4446],{"id":1525,"depth":273,"text":390},{"id":1749,"depth":273,"text":1749},{"id":1784,"depth":273,"text":1784},{"id":193,"depth":251,"text":193,"children":4448},[4449,4450],{"id":2237,"depth":273,"text":2237},{"id":2794,"depth":273,"text":2794},{"id":2805,"depth":251,"text":2805,"children":4452},[4453,4454],{"id":2808,"depth":273,"text":2809},{"id":2965,"depth":273,"text":2965},{"id":3258,"depth":251,"text":3258,"children":4456},[4457,4458],{"id":3261,"depth":273,"text":3261},{"id":3395,"depth":273,"text":3395},{"id":3487,"depth":251,"text":3488,"children":4460},[4461,4462,4463],{"id":3491,"depth":273,"text":3492},{"id":3684,"depth":273,"text":3685},{"id":3855,"depth":273,"text":3855},{"id":3885,"depth":251,"text":3885,"children":4465},[4466,4467,4468],{"id":3888,"depth":273,"text":3889},{"id":4022,"depth":273,"text":4023},{"id":4229,"depth":273,"text":4229},{"id":4244,"depth":251,"text":4244},{"id":4326,"depth":251,"text":4326},{"id":4384,"depth":251,"text":4384},"Nuxt","2026-01-22","使用 Pinia Colada 管理非同步狀態，實作 useQuery 查詢、useMutation 變更與快取策略。",false,"md",null,{},"\u002Fblog\u002Fnuxt\u002Fpinia-colada-async-state",{"title":5,"description":4474},"nuxt-fullstack","Nuxt 4 全棧實戰筆記","blog\u002Fnuxt\u002Fpinia-colada-async-state\u002Findex",[4472,4485,4486],"Nitro","Pinia","lc6OYvX_tMISL7bs7Kwvz8cX_VXrTL7uhuW8XU0o5zU",1780512499430]