[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"i-ri:search-line":3,"i-ri:moon-line":8,"i-ri:sun-line":10,"i-ri:menu-3-line":12,"i-ri:close-line":14,"notes-module-items-react":16,"notes-page-react-11-data-layer\u002F02-tanstack-query-caching-and-invalidation":494,"i-ri:arrow-left-s-line":1634,"i-ri:menu-2-line":1636,"i-ri:arrow-right-s-line":1638,"i-ep:copy-document":1640},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"currentColor\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"currentColor\" d=\"M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2h.1A6.98 6.98 0 0 0 10 7m-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938A8 8 0 0 0 4 12\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cpath fill=\"currentColor\" d=\"M12 18a6 6 0 1 1 0-12a6 6 0 0 1 0 12m0-2a4 4 0 1 0 0-8a4 4 0 0 0 0 8M11 1h2v3h-2zm0 19h2v3h-2zM3.515 4.929l1.414-1.414L7.05 5.636L5.636 7.05zM16.95 18.364l1.414-1.414l2.121 2.121l-1.414 1.414zm2.121-14.85l1.414 1.415l-2.121 2.121l-1.414-1.414zM5.636 16.95l1.414 1.414l-2.121 2.121l-1.414-1.414zM23 11v2h-3v-2zM4 11v2H1v-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm6 7h12v2H9zm-6 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cpath fill=\"currentColor\" d=\"m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z\"\u002F>",[17,22,26,30,34,38,42,46,50,54,58,62,66,70,74,78,82,86,90,94,98,102,106,110,114,118,122,126,130,134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,254,258,262,266,270,274,278,282,286,290,294,298,302,306,310,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,454,458,462,466,470,474,478,482,486,490],{"path":18,"title":19,"meta":20},"\u002Fnotes\u002Freact\u002F01-basics\u002F01-how-to-read-this-repo","如何阅读本仓库（学习路径与章节依赖）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},"2026-11-05T09:47:15.000Z",{"path":23,"title":24,"meta":25},"\u002Fnotes\u002Freact\u002F01-basics\u002F02-render-vs-commit","React 渲染两阶段：Render vs Commit（总览）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":27,"title":28,"meta":29},"\u002Fnotes\u002Freact\u002F01-basics\u002F03-update-pipeline-birdview","从“更新”到“页面变更”：一次 setState 的全链路鸟瞰",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":31,"title":32,"meta":33},"\u002Fnotes\u002Freact\u002F01-basics","基础入门（建议先读）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":35,"title":36,"meta":37},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F01-browser-multi-process","浏览器多进程架构",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":39,"title":40,"meta":41},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F02-event-loop-overview","事件循环概述",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":43,"title":44,"meta":45},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F03-call-stack","函数调用栈",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":47,"title":48,"meta":49},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F04-threads","线程介绍",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":51,"title":52,"meta":53},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F05-refresh-rate-and-queues","刷新率与执行队列",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":55,"title":56,"meta":57},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F06-settimeout","setTimeout 原理详解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":59,"title":60,"meta":61},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F07-promise","Promise 原理详解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":63,"title":64,"meta":65},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F08-event-loop-in-practice","事件循环机制（综合）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":67,"title":68,"meta":69},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F09-priority-queues","优先级队列",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":71,"title":72,"meta":73},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F01-concept","并发模式：概念",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":75,"title":76,"meta":77},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F02-demo","案例演示并发模式",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":79,"title":80,"meta":81},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F03-high-priority-preemption","高优先级插队",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":83,"title":84,"meta":85},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F04-preemption-vs-interruption","插队的影响、与中断的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":87,"title":88,"meta":89},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F05-shouldYield","中断条件：shouldYield",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":91,"title":92,"meta":93},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F06-react-tasks-and-queues","React 中的任务与队列",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":95,"title":96,"meta":97},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F07-ensureRootIsScheduled","ensureRootIsScheduled",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":99,"title":100,"meta":101},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F08-batch-updates-merge","合并多个更新触发",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":103,"title":104,"meta":105},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F09-taskQueue-lifecycle","taskQueue 队列循环的启动与结束",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":107,"title":108,"meta":109},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F10-time-slicing","时间切片是如何实现的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":111,"title":112,"meta":113},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F11-workLoop-full","workLoop 循环完整逻辑",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":115,"title":116,"meta":117},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F12-priority-design","React 中的优先级设计",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":119,"title":120,"meta":121},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F13-lane-model","lane 模型",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":123,"title":124,"meta":125},"\u002Fnotes\u002Freact\u002F04-fiber\u002F01-three-node-types","三种节点对象",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":127,"title":128,"meta":129},"\u002Fnotes\u002Freact\u002F04-fiber\u002F02-fiberRootNode","FiberRootNode",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":131,"title":132,"meta":133},"\u002Fnotes\u002Freact\u002F04-fiber\u002F03-fiber-tree","Fiber 树",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":135,"title":136,"meta":137},"\u002Fnotes\u002Freact\u002F04-fiber\u002F04-initial-mount-build","Fiber 树初始构建过程",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":139,"title":140,"meta":141},"\u002Fnotes\u002Freact\u002F04-fiber\u002F05-workLoopConcurrent","workLoopConcurrent",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":143,"title":144,"meta":145},"\u002Fnotes\u002Freact\u002F04-fiber\u002F06-stack-and-workInProgress","栈结构 与 workInProgress",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":147,"title":148,"meta":149},"\u002Fnotes\u002Freact\u002F04-fiber\u002F07-executionContext","执行上下文 executionContext",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":151,"title":152,"meta":153},"\u002Fnotes\u002Freact\u002F04-fiber\u002F08-update-lanes","update lanes",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":155,"title":156,"meta":157},"\u002Fnotes\u002Freact\u002F04-fiber\u002F09-render-lanes","render lanes",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":159,"title":160,"meta":161},"\u002Fnotes\u002Freact\u002F04-fiber\u002F10-fiber-lanes","fiber lanes",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":163,"title":164,"meta":165},"\u002Fnotes\u002Freact\u002F04-fiber\u002F11-flags-appendix","附录：flags",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":167,"title":168,"meta":169},"\u002Fnotes\u002Freact\u002F05-hooks\u002F01-background","hook 背景",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":171,"title":172,"meta":173},"\u002Fnotes\u002Freact\u002F05-hooks\u002F02-categories","hook 分类",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":175,"title":176,"meta":177},"\u002Fnotes\u002Freact\u002F05-hooks\u002F03-closures","hook 与闭包",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":179,"title":180,"meta":181},"\u002Fnotes\u002Freact\u002F05-hooks\u002F04-hooks-and-fiber","hook 与 fiber",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":183,"title":184,"meta":185},"\u002Fnotes\u002Freact\u002F05-hooks\u002F05-renderWithHooks","renderWithHooks",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":187,"title":188,"meta":189},"\u002Fnotes\u002Freact\u002F05-hooks\u002F06-init-state-hook","初始化 State Hook",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":191,"title":192,"meta":193},"\u002Fnotes\u002Freact\u002F05-hooks\u002F07-init-effect-hook","初始化 effect Hook",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":195,"title":196,"meta":197},"\u002Fnotes\u002Freact\u002F05-hooks\u002F08-circular-linked-list","环形链表详解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":199,"title":200,"meta":201},"\u002Fnotes\u002Freact\u002F05-hooks\u002F09-useReducer-vs-useState","useReducer 与 useState 的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":203,"title":204,"meta":205},"\u002Fnotes\u002Freact\u002F05-hooks\u002F10-update-linked-list","update 链表",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":207,"title":208,"meta":209},"\u002Fnotes\u002Freact\u002F05-hooks\u002F11-mount-state-updates","初始阶段的状态更新",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":211,"title":212,"meta":213},"\u002Fnotes\u002Freact\u002F05-hooks\u002F12-baseQueue-vs-pending","baseQueue 与 queue.pending",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":215,"title":216,"meta":217},"\u002Fnotes\u002Freact\u002F05-hooks\u002F13-dispatch-in-update","更新阶段的 dispatch",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":219,"title":220,"meta":221},"\u002Fnotes\u002Freact\u002F05-hooks\u002F14-commitRoot","commitRoot",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":223,"title":224,"meta":225},"\u002Fnotes\u002Freact\u002F06-diff\u002F01-update-overview","React 更新机制概述",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":227,"title":228,"meta":229},"\u002Fnotes\u002Freact\u002F06-diff\u002F02-diff-strategy","diff 策略",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":231,"title":232,"meta":233},"\u002Fnotes\u002Freact\u002F06-diff\u002F03-node-compare","节点比较方式",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":235,"title":236,"meta":237},"\u002Fnotes\u002Freact\u002F06-diff\u002F04-reconcileChildFibers","reconcileChildFibers",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":239,"title":240,"meta":241},"\u002Fnotes\u002Freact\u002F06-diff\u002F05-reconcileSingleElement","reconcileSingleElement",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":243,"title":244,"meta":245},"\u002Fnotes\u002Freact\u002F06-diff\u002F06-reconcileChildrenArray","reconcileChildrenArray",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":247,"title":248,"meta":249},"\u002Fnotes\u002Freact\u002F06-diff\u002F07-why-not-number-key","为什么不建议使用数字作为 key",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":251,"title":252,"meta":253},"\u002Fnotes\u002Freact\u002F07-event-system\u002F01-overview","事件系统概述",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":255,"title":256,"meta":257},"\u002Fnotes\u002Freact\u002F07-event-system\u002F02-event-plugin","事件插件",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":259,"title":260,"meta":261},"\u002Fnotes\u002Freact\u002F07-event-system\u002F03-event-pooling","事件池",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":263,"title":264,"meta":265},"\u002Fnotes\u002Freact\u002F07-event-system\u002F04-root-listeners","根节点事件绑定",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":267,"title":268,"meta":269},"\u002Fnotes\u002Freact\u002F07-event-system\u002F05-event-dispatch","事件触发",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":271,"title":272,"meta":273},"\u002Fnotes\u002Freact\u002F08-interview\u002F01-useEffect-vs-useLayoutEffect","useEffect 与 useLayoutEffect 的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":275,"title":276,"meta":277},"\u002Fnotes\u002Freact\u002F08-interview\u002F02-why-no-conditional-hooks","为什么 hook 不能写在条件判断里",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":279,"title":280,"meta":281},"\u002Fnotes\u002Freact\u002F08-interview\u002F03-understanding-concurrency","聊聊在 React 中，你对并发模式的理解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":283,"title":284,"meta":285},"\u002Fnotes\u002Freact\u002F08-interview\u002F04-update-mechanism","聊聊 React 的更新机制原理",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":287,"title":288,"meta":289},"\u002Fnotes\u002Freact\u002F08-interview\u002F05-setState-sync-or-async","setState 是同步还是异步的？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":291,"title":292,"meta":293},"\u002Fnotes\u002Freact\u002F08-interview\u002F06-useState-vs-useReducer","聊聊 useState 与 useReducer 的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":295,"title":296,"meta":297},"\u002Fnotes\u002Freact\u002F08-interview\u002F07-closure-trap","聊聊闭包陷阱问题，以及如何解决",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":299,"title":300,"meta":301},"\u002Fnotes\u002Freact\u002F08-interview\u002F08-time-slicing-details","时间分片是如何实现的（任务拆分\u002F中断\u002F恢复）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":303,"title":304,"meta":305},"\u002Fnotes\u002Freact\u002F08-interview\u002F09-batched-updates-useState","聊聊 useState 的批处理更新机制",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":307,"title":308,"meta":309},"\u002Fnotes\u002Freact\u002F08-interview\u002F10-jsx-to-dom","JSX 是如何转变成为真实 DOM 的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":311,"title":312,"meta":313},"\u002Fnotes\u002Freact\u002F08-interview\u002F11-useCallback-impl","useCallback 的实现原理是什么",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":315,"title":316,"meta":317},"\u002Fnotes\u002Freact\u002F08-interview\u002F12-scheduling-mechanism","详细聊聊 React 的调度机制",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":319,"title":320,"meta":321},"\u002Fnotes\u002Freact\u002F08-interview\u002F13-priority-and-lanes","聊聊 React 的优先级机制（Lane 模型）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":323,"title":324,"meta":325},"\u002Fnotes\u002Freact\u002F08-interview\u002F14-diff-algorithm","React 的 Diff 算法是什么样的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":327,"title":328,"meta":329},"\u002Fnotes\u002Freact\u002F08-interview\u002F15-event-system","详细聊聊 React 的事件系统是如何实现的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":331,"title":332,"meta":333},"\u002Fnotes\u002Freact\u002F08-interview\u002F16-portals-bubbling","React Portals 上的事件是否会冒泡到父组件，原理是什么",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":335,"title":336,"meta":337},"\u002Fnotes\u002Freact\u002F08-interview\u002F17-useEffect-impl","useEffect 的实现原理是什么",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":339,"title":340,"meta":341},"\u002Fnotes\u002Freact\u002F08-interview\u002F18-useContext-impl","请聊聊 useContext 的实现原理",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":343,"title":344,"meta":345},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F01-automatic-batching-and-flushsync","React 18 自动批处理（Automatic Batching）与 flushSync",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":347,"title":348,"meta":349},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F02-strictmode-and-idempotent-effects","React StrictMode：为什么会“双调用”？（源码\u002F机制视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":351,"title":352,"meta":353},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F03-transition-useTransition-useDeferredValue","Transition：startTransition \u002F useTransition \u002F useDeferredValue（机制视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":355,"title":356,"meta":357},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F04-suspense-loading-boundary-design","Suspense：加载态边界如何设计（机制\u002F架构视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":359,"title":360,"meta":361},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F05-error-boundary-reporting-and-recovery","Error Boundary：兜底、重试与上报（自研 vs Sentry）（机制\u002F架构视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":363,"title":364,"meta":365},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice","React 18 实战（并发特性与默认行为）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":367,"title":368,"meta":369},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation\u002F01-routing-and-url-state-mental-model","路由与 URL State：统一心智模型（架构师视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":371,"title":372,"meta":373},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation\u002F02-tanstack-router-route-tree-search-loader-prefetch","TanStack Router（Vite \u002F SPA）：Route Tree \u002F Search \u002F Loader \u002F Prefetch（落地篇）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":375,"title":376,"meta":377},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation\u002F03-next-app-router-segments-layout-loading-error-not-found-prefetch","Next.js App Router：Segments \u002F Layouts \u002F Loading-Error-NotFound \u002F Prefetch（落地篇）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":379,"title":380,"meta":381},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation","路由与导航（TanStack Router \u002F Next App Router）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":383,"title":384,"meta":385},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F01-state-layering-ui-server-url-global","状态分层：UI \u002F Server \u002F URL \u002F Global（架构师视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":387,"title":388,"meta":389},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F02-tanstack-query-caching-and-invalidation","TanStack Query：缓存模型与失效策略（Caching & Invalidation）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":391,"title":392,"meta":393},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F03-optimistic-updates-and-consistency","TanStack Query：乐观更新与一致性（Optimistic Updates & Consistency）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":395,"title":396,"meta":397},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F04-form-architecture-react-hook-form-validation-performance-testability","表单架构：React Hook Form 的受控\u002F非受控、校验、性能与可测试性（架构师视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":399,"title":400,"meta":401},"\u002Fnotes\u002Freact\u002F11-data-layer","数据层（Server State \u002F 表单 \u002F 状态分层）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":403,"title":404,"meta":405},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F01-hydration-mismatch","Hydration mismatch（React \u002F Next.js）：成因、检测、排查清单与工程化规避",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":407,"title":408,"meta":409},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F01-nextjs-cache-revalidate-consistency-online-not-updating","Next.js 缓存\u002F重验证与一致性：避免「线上怎么不更新」事故（App Router）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":411,"title":412,"meta":413},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F02-csr-ssr-ssg-isr-how-to-choose","CSR vs SSR vs SSG vs ISR：怎么选？边界是什么？（体验 + 成本 + 一致性）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":415,"title":416,"meta":417},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F04-streaming-ssr-with-suspense","Streaming SSR + Suspense：提升前端感知性能的利器",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":419,"title":420,"meta":421},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery","渲染与交付（CSR\u002FSSR\u002FStreaming\u002FHydration\u002F缓存）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":423,"title":424,"meta":425},"\u002Fnotes\u002Freact\u002F13-production-readiness\u002F01-observability-logging-metrics-tracing","前端可观测性体系：日志、指标与链路追踪",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":427,"title":428,"meta":429},"\u002Fnotes\u002Freact\u002F13-production-readiness\u002F02-auth-and-web-security","鉴权与 Web 安全：OAuth, JWT, XSS, CSRF, CSP",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":431,"title":432,"meta":433},"\u002Fnotes\u002Freact\u002F13-production-readiness","生产可用性（错误\u002F可观测\u002F鉴权\u002F安全）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":435,"title":436,"meta":437},"\u002Fnotes\u002Freact\u002F14-performance\u002F01-performance-playbook-and-metrics","前端性能定位 Playbook：从指标到归因",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":439,"title":440,"meta":441},"\u002Fnotes\u002Freact\u002F14-performance\u002F02-rendering-optimization-memo-context-virtualization","React 渲染性能优化：Memo, Context, 与虚拟化",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":443,"title":444,"meta":445},"\u002Fnotes\u002Freact\u002F14-performance\u002F03-asset-and-bundle-optimization","资源与 Bundle 优化：代码分割、图片与 CDN",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":447,"title":448,"meta":449},"\u002Fnotes\u002Freact\u002F14-performance","性能体系（定位 → 优化 → 度量）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":451,"title":452,"meta":453},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F01-component-system-and-design-system","组件体系与设计系统：构建规模化前端的基石",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":455,"title":456,"meta":457},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F02-testing-strategy-rtl-e2e-testability","前端测试体系：RTL, E2E 与可测性设计",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":459,"title":460,"meta":461},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F03-monorepo-and-dependency-management","Monorepo 与依赖治理：pnpm 和 Turborepo",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":463,"title":464,"meta":465},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F04-cicd-and-quality-gates","CI\u002FCD 与质量门禁：构建可靠的自动化流程",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":467,"title":468,"meta":469},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F05-bff-and-api-design","BFF 与 API 设计：前端架构师的视角",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":471,"title":472,"meta":473},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture","工程与架构治理（规模化）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":475,"title":476,"meta":477},"\u002Fnotes\u002Freact\u002F16-advanced\u002F01-rsc-and-server-actions-deep-dive","RSC\u002FServer Actions 深水区：边界、约束与缓存一致性",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":479,"title":480,"meta":481},"\u002Fnotes\u002Freact\u002F16-advanced\u002F02-micro-frontend-governance","微前端治理：样式、路由与通信",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":483,"title":484,"meta":485},"\u002Fnotes\u002Freact\u002F16-advanced\u002F03-realtime-and-offline","实时与离线：WebSocket, PWA 与 Service Worker",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":487,"title":488,"meta":489},"\u002Fnotes\u002Freact\u002F16-advanced\u002F04-a11y-i18n-compliance","a11y, i18n 与合规：构建负责任的全球化应用",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":491,"title":492,"meta":493},"\u002Fnotes\u002Freact\u002F16-advanced","进阶专题（按业务需要选做）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"id":495,"type":496,"sourcePath":497,"routePath":387,"path":387,"title":388,"updatedAt":21,"meta":498,"body":500,"toc":1602},"bm90ZTpub3Rlcy9yZWFjdC8xMS1kYXRhLWxheWVyLzAyLXRhbnN0YWNrLXF1ZXJ5LWNhY2hpbmctYW5kLWludmFsaWRhdGlvbi5tZA","note","notes\u002Freact\u002F11-data-layer\u002F02-tanstack-query-caching-and-invalidation.md",{"id":495,"type":496,"sourcePath":497,"slug":499,"title":388,"updatedAt":21,"lastUpdated":21},"react\u002F11-data-layer\u002F02-tanstack-query-caching-and-invalidation",{"type":501,"children":502},"root",[503,511,549,556,561,576,581,589,594,607,613,620,634,647,655,660,687,693,698,703,709,715,729,734,757,763,777,781,794,802,808,814,827,832,840,846,854,858,871,877,882,896,904,917,938,946,952,957,975,980,998,1004,1009,1027,1032,1050,1056,1062,1067,1080,1085,1098,1104,1109,1122,1127,1150,1155,1161,1167,1200,1206,1227,1233,1239,1457,1463,1468,1486,1492,1545,1550,1596],{"type":504,"tag":505,"props":506,"children":508},"element","h1",{"id":507},"tanstack-query缓存模型与失效策略caching-invalidation",[509],{"type":510,"value":388},"text",{"type":504,"tag":512,"props":513,"children":514},"blockquote",{},[515],{"type":504,"tag":516,"props":517,"children":518},"p",{},[519,521,527,529,534,535,540,542,547],{"type":510,"value":520},"一句话结论：TanStack Query（React Query）把 Server State 当成“带缓存一致性的查询结果”来管理——你不再手写 loading\u002Ferror\u002F缓存\u002F去重，而是通过 ",{"type":504,"tag":522,"props":523,"children":524},"strong",{},[525],{"type":510,"value":526},"queryKey（身份）",{"type":510,"value":528}," + ",{"type":504,"tag":522,"props":530,"children":531},{},[532],{"type":510,"value":533},"stale\u002Fgc（生命周期）",{"type":510,"value":528},{"type":504,"tag":522,"props":536,"children":537},{},[538],{"type":510,"value":539},"invalidate\u002Frefetch（失效与刷新）",{"type":510,"value":541}," 建立一套可控的数据一致性系统；真正的工程关键是：",{"type":504,"tag":522,"props":543,"children":544},{},[545],{"type":510,"value":546},"queryKey 设计、失效粒度、预取策略、以及与 URL State \u002F 路由 \u002F Next 缓存的边界",{"type":510,"value":548},"。",{"type":504,"tag":550,"props":551,"children":553},"h2",{"id":552},"_0-前置它管理的是-server-state不是所有状态",[554],{"type":510,"value":555},"0. 前置：它管理的是 Server State，不是所有状态",{"type":504,"tag":516,"props":557,"children":558},{},[559],{"type":510,"value":560},"在上一篇“状态分层”里我们强调：",{"type":504,"tag":562,"props":563,"children":564},"ul",{},[565,571],{"type":504,"tag":566,"props":567,"children":568},"li",{},[569],{"type":510,"value":570},"URL State（筛选\u002F分页\u002F排序）应以 URL 为真相",{"type":504,"tag":566,"props":572,"children":573},{},[574],{"type":510,"value":575},"Server State（列表\u002F详情等）应以 Query cache 为真相",{"type":504,"tag":516,"props":577,"children":578},{},[579],{"type":510,"value":580},"TanStack Query 适合管理：",{"type":504,"tag":562,"props":582,"children":583},{},[584],{"type":504,"tag":566,"props":585,"children":586},{},[587],{"type":510,"value":588},"“来自服务端 + 需要缓存一致性”的数据",{"type":504,"tag":516,"props":590,"children":591},{},[592],{"type":510,"value":593},"不适合用它承载：",{"type":504,"tag":562,"props":595,"children":596},{},[597,602],{"type":504,"tag":566,"props":598,"children":599},{},[600],{"type":510,"value":601},"UI state（弹窗开关）",{"type":504,"tag":566,"props":603,"children":604},{},[605],{"type":510,"value":606},"纯全局配置但不依赖请求一致性的状态（例如主题）",{"type":504,"tag":550,"props":608,"children":610},{"id":609},"_1-query-的核心对象querykey-与-queryfn",[611],{"type":510,"value":612},"1. Query 的核心对象：queryKey 与 queryFn",{"type":504,"tag":614,"props":615,"children":617},"h3",{"id":616},"_11-querykey缓存的身份",[618],{"type":510,"value":619},"1.1 queryKey：缓存的“身份”",{"type":504,"tag":516,"props":621,"children":622},{},[623,625,632],{"type":510,"value":624},"你可以把 ",{"type":504,"tag":626,"props":627,"children":629},"code",{"className":628},[],[630],{"type":510,"value":631},"queryKey",{"type":510,"value":633}," 当成缓存系统的主键（cache key）。",{"type":504,"tag":562,"props":635,"children":636},{},[637,642],{"type":504,"tag":566,"props":638,"children":639},{},[640],{"type":510,"value":641},"key 相同 → 命中同一份缓存",{"type":504,"tag":566,"props":643,"children":644},{},[645],{"type":510,"value":646},"key 不同 → 视为不同查询（不同缓存槽）",{"type":504,"tag":516,"props":648,"children":649},{},[650],{"type":504,"tag":522,"props":651,"children":652},{},[653],{"type":510,"value":654},"工程建议：queryKey 必须只包含“决定结果”的输入”。",{"type":504,"tag":516,"props":656,"children":657},{},[658],{"type":510,"value":659},"例如：",{"type":504,"tag":562,"props":661,"children":662},{},[663,674],{"type":504,"tag":566,"props":664,"children":665},{},[666,668],{"type":510,"value":667},"✅ ",{"type":504,"tag":626,"props":669,"children":671},{"className":670},[],[672],{"type":510,"value":673},"['products', { keyword, page, sort, filters }]",{"type":504,"tag":566,"props":675,"children":676},{},[677,679,685],{"type":510,"value":678},"❌ ",{"type":504,"tag":626,"props":680,"children":682},{"className":681},[],[683],{"type":510,"value":684},"['products', { keyword, page }, { uiOpen: true }]",{"type":510,"value":686},"（把 UI state 混进来会导致缓存碎片化）",{"type":504,"tag":614,"props":688,"children":690},{"id":689},"_12-queryfn如何获取",[691],{"type":510,"value":692},"1.2 queryFn：如何获取",{"type":504,"tag":516,"props":694,"children":695},{},[696],{"type":510,"value":697},"Query 负责“缓存与一致性”，而 queryFn 负责“请求”。",{"type":504,"tag":516,"props":699,"children":700},{},[701],{"type":510,"value":702},"建议收敛在统一的 API 层（带鉴权、traceId、错误规范），避免 queryFn 到处散落。",{"type":504,"tag":550,"props":704,"children":706},{"id":705},"_2-缓存生命周期staletime-gctime原-cachetime",[707],{"type":510,"value":708},"2. 缓存生命周期：staleTime \u002F gcTime（原 cacheTime）",{"type":504,"tag":614,"props":710,"children":712},{"id":711},"_21-stale是否新鲜",[713],{"type":510,"value":714},"2.1 stale：是否“新鲜”",{"type":504,"tag":562,"props":716,"children":717},{},[718],{"type":504,"tag":566,"props":719,"children":720},{},[721,727],{"type":504,"tag":626,"props":722,"children":724},{"className":723},[],[725],{"type":510,"value":726},"staleTime",{"type":510,"value":728},"：数据在多久内视为“新鲜”（不会因为重新挂载就自动 refetch）",{"type":504,"tag":516,"props":730,"children":731},{},[732],{"type":510,"value":733},"理解方式：",{"type":504,"tag":562,"props":735,"children":736},{},[737,747],{"type":504,"tag":566,"props":738,"children":739},{},[740,745],{"type":504,"tag":522,"props":741,"children":742},{},[743],{"type":510,"value":744},"staleTime 越大",{"type":510,"value":746},"：更少自动刷新，更依赖你主动 invalidate（适合稳定数据、降低请求）",{"type":504,"tag":566,"props":748,"children":749},{},[750,755],{"type":504,"tag":522,"props":751,"children":752},{},[753],{"type":510,"value":754},"staleTime 越小",{"type":510,"value":756},"：更频繁自动刷新（适合强一致需求，但要控制请求风暴）",{"type":504,"tag":614,"props":758,"children":760},{"id":759},"_22-gc缓存何时被垃圾回收",[761],{"type":510,"value":762},"2.2 gc：缓存何时被垃圾回收",{"type":504,"tag":562,"props":764,"children":765},{},[766],{"type":504,"tag":566,"props":767,"children":768},{},[769,775],{"type":504,"tag":626,"props":770,"children":772},{"className":771},[],[773],{"type":510,"value":774},"gcTime",{"type":510,"value":776},"：当某个 query 没有观察者（没有组件在用）后，多久清掉缓存",{"type":504,"tag":516,"props":778,"children":779},{},[780],{"type":510,"value":733},{"type":504,"tag":562,"props":782,"children":783},{},[784,789],{"type":504,"tag":566,"props":785,"children":786},{},[787],{"type":510,"value":788},"gcTime 影响“返回上一页是否秒开”",{"type":504,"tag":566,"props":790,"children":791},{},[792],{"type":510,"value":793},"对移动端、低内存设备要更谨慎",{"type":504,"tag":512,"props":795,"children":796},{},[797],{"type":504,"tag":516,"props":798,"children":799},{},[800],{"type":510,"value":801},"版本提示：新版本把 cacheTime 更名为 gcTime，语义更准确。",{"type":504,"tag":550,"props":803,"children":805},{"id":804},"_3-失效与刷新invalidatequeries-vs-refetchqueries",[806],{"type":510,"value":807},"3. 失效与刷新：invalidateQueries vs refetchQueries",{"type":504,"tag":614,"props":809,"children":811},{"id":810},"_31-invalidatequeries让缓存变脏",[812],{"type":510,"value":813},"3.1 invalidateQueries：让缓存变“脏”",{"type":504,"tag":562,"props":815,"children":816},{},[817,822],{"type":504,"tag":566,"props":818,"children":819},{},[820],{"type":510,"value":821},"将匹配的 query 标记为 stale",{"type":504,"tag":566,"props":823,"children":824},{},[825],{"type":510,"value":826},"下一次合适的时机（组件在用、或配置允许）会触发 refetch",{"type":504,"tag":516,"props":828,"children":829},{},[830],{"type":510,"value":831},"适合场景：",{"type":504,"tag":562,"props":833,"children":834},{},[835],{"type":504,"tag":566,"props":836,"children":837},{},[838],{"type":510,"value":839},"你完成了 mutation（新增\u002F编辑\u002F删除），需要让相关列表\u002F详情在后续刷新",{"type":504,"tag":614,"props":841,"children":843},{"id":842},"_32-refetchqueries立即重新拉取",[844],{"type":510,"value":845},"3.2 refetchQueries：立即重新拉取",{"type":504,"tag":562,"props":847,"children":848},{},[849],{"type":504,"tag":566,"props":850,"children":851},{},[852],{"type":510,"value":853},"直接发起请求刷新",{"type":504,"tag":516,"props":855,"children":856},{},[857],{"type":510,"value":831},{"type":504,"tag":562,"props":859,"children":860},{},[861,866],{"type":504,"tag":566,"props":862,"children":863},{},[864],{"type":510,"value":865},"用户显式点击“刷新”",{"type":504,"tag":566,"props":867,"children":868},{},[869],{"type":510,"value":870},"你明确知道必须立刻同步 UI",{"type":504,"tag":614,"props":872,"children":874},{"id":873},"_33-工程策略通常-mutation-后用-invalidate-而不是手动-setquerydata",[875],{"type":510,"value":876},"3.3 工程策略：通常 mutation 后用 invalidate 而不是手动 setQueryData",{"type":504,"tag":516,"props":878,"children":879},{},[880],{"type":510,"value":881},"两种路线：",{"type":504,"tag":883,"props":884,"children":885},"ol",{},[886],{"type":504,"tag":566,"props":887,"children":888},{},[889,894],{"type":504,"tag":522,"props":890,"children":891},{},[892],{"type":510,"value":893},"Invalidate 驱动（推荐默认）",{"type":510,"value":895},"：",{"type":504,"tag":562,"props":897,"children":898},{},[899],{"type":504,"tag":566,"props":900,"children":901},{},[902],{"type":510,"value":903},"mutation 成功 → invalidate 相关 queries → 由 query 统一刷新",{"type":504,"tag":883,"props":905,"children":907},{"start":906},2,[908],{"type":504,"tag":566,"props":909,"children":910},{},[911,916],{"type":504,"tag":522,"props":912,"children":913},{},[914],{"type":510,"value":915},"Cache Update 驱动（进阶）",{"type":510,"value":895},{"type":504,"tag":562,"props":918,"children":919},{},[920,933],{"type":504,"tag":566,"props":921,"children":922},{},[923,925,931],{"type":510,"value":924},"mutation 成功 → ",{"type":504,"tag":626,"props":926,"children":928},{"className":927},[],[929],{"type":510,"value":930},"setQueryData",{"type":510,"value":932}," 直接更新缓存（速度快）",{"type":504,"tag":566,"props":934,"children":935},{},[936],{"type":510,"value":937},"再在后台 invalidate 做一致性兜底",{"type":504,"tag":512,"props":939,"children":940},{},[941],{"type":504,"tag":516,"props":942,"children":943},{},[944],{"type":510,"value":945},"经验：架构上应先把 invalidate 体系建立好，再逐步引入 setQueryData\u002F乐观更新。",{"type":504,"tag":550,"props":947,"children":949},{"id":948},"_4-并发去重与状态机你不再手写请求锁",[950],{"type":510,"value":951},"4. 并发去重与状态机：你不再手写“请求锁”",{"type":504,"tag":516,"props":953,"children":954},{},[955],{"type":510,"value":956},"TanStack Query 默认能处理很多工程脏活：",{"type":504,"tag":562,"props":958,"children":959},{},[960,965,970],{"type":504,"tag":566,"props":961,"children":962},{},[963],{"type":510,"value":964},"同一 queryKey 多组件订阅：共享一份请求与结果",{"type":504,"tag":566,"props":966,"children":967},{},[968],{"type":510,"value":969},"loading\u002Ferror\u002Fsuccess 状态统一",{"type":504,"tag":566,"props":971,"children":972},{},[973],{"type":510,"value":974},"retry\u002Fbackoff、cancel、focus\u002Frefetch 等策略",{"type":504,"tag":516,"props":976,"children":977},{},[978],{"type":510,"value":979},"你应该把精力放在：",{"type":504,"tag":562,"props":981,"children":982},{},[983,988,993],{"type":504,"tag":566,"props":984,"children":985},{},[986],{"type":510,"value":987},"key 设计",{"type":504,"tag":566,"props":989,"children":990},{},[991],{"type":510,"value":992},"失效粒度",{"type":504,"tag":566,"props":994,"children":995},{},[996],{"type":510,"value":997},"与路由\u002FURL 的协作",{"type":504,"tag":550,"props":999,"children":1001},{"id":1000},"_5-与-url-state-的协作url-是条件真相querykey-是缓存真相",[1002],{"type":510,"value":1003},"5. 与 URL State 的协作：URL 是条件真相，QueryKey 是缓存真相",{"type":504,"tag":516,"props":1005,"children":1006},{},[1007],{"type":510,"value":1008},"典型模式（强烈推荐）：",{"type":504,"tag":883,"props":1010,"children":1011},{},[1012,1017,1022],{"type":504,"tag":566,"props":1013,"children":1014},{},[1015],{"type":510,"value":1016},"把筛选\u002F分页等条件放进 URL（source of truth）",{"type":504,"tag":566,"props":1018,"children":1019},{},[1020],{"type":510,"value":1021},"从 URL 派生 queryKey",{"type":504,"tag":566,"props":1023,"children":1024},{},[1025],{"type":510,"value":1026},"Query 使用 queryKey 拉数据并缓存",{"type":504,"tag":516,"props":1028,"children":1029},{},[1030],{"type":510,"value":1031},"这样保证：",{"type":504,"tag":562,"props":1033,"children":1034},{},[1035,1040,1045],{"type":504,"tag":566,"props":1036,"children":1037},{},[1038],{"type":510,"value":1039},"分享链接可还原",{"type":504,"tag":566,"props":1041,"children":1042},{},[1043],{"type":510,"value":1044},"back\u002Fforward 可回放",{"type":504,"tag":566,"props":1046,"children":1047},{},[1048],{"type":510,"value":1049},"缓存命中稳定（同一 URL → 同一 key）",{"type":504,"tag":550,"props":1051,"children":1053},{"id":1052},"_6-预取prefetch把等待前移提升导航体验",[1054],{"type":510,"value":1055},"6. 预取（prefetch）：把“等待”前移，提升导航体验",{"type":504,"tag":614,"props":1057,"children":1059},{"id":1058},"_61-spatanstack-router-vite",[1060],{"type":510,"value":1061},"6.1 SPA（TanStack Router + Vite）",{"type":504,"tag":516,"props":1063,"children":1064},{},[1065],{"type":510,"value":1066},"常见做法：",{"type":504,"tag":562,"props":1068,"children":1069},{},[1070,1075],{"type":504,"tag":566,"props":1071,"children":1072},{},[1073],{"type":510,"value":1074},"路由进入前：prefetch list",{"type":504,"tag":566,"props":1076,"children":1077},{},[1078],{"type":510,"value":1079},"hover 链接：prefetch detail",{"type":504,"tag":516,"props":1081,"children":1082},{},[1083],{"type":510,"value":1084},"关键点：",{"type":504,"tag":562,"props":1086,"children":1087},{},[1088,1093],{"type":504,"tag":566,"props":1089,"children":1090},{},[1091],{"type":510,"value":1092},"prefetch 使用同一套 queryKey（否则预取无法命中）",{"type":504,"tag":566,"props":1094,"children":1095},{},[1096],{"type":510,"value":1097},"预取要有预算（别把用户带宽打满）",{"type":504,"tag":614,"props":1099,"children":1101},{"id":1100},"_62-nextjs",[1102],{"type":510,"value":1103},"6.2 Next.js",{"type":504,"tag":516,"props":1105,"children":1106},{},[1107],{"type":510,"value":1108},"在 Next（尤其 App Router）里你可能会同时面对两套缓存：",{"type":504,"tag":562,"props":1110,"children":1111},{},[1112,1117],{"type":504,"tag":566,"props":1113,"children":1114},{},[1115],{"type":510,"value":1116},"Next 的 fetch 缓存\u002F重验证（偏框架级）",{"type":504,"tag":566,"props":1118,"children":1119},{},[1120],{"type":510,"value":1121},"TanStack Query 的 client cache（偏交互级）",{"type":504,"tag":516,"props":1123,"children":1124},{},[1125],{"type":510,"value":1126},"架构建议：",{"type":504,"tag":562,"props":1128,"children":1129},{},[1130,1140],{"type":504,"tag":566,"props":1131,"children":1132},{},[1133,1138],{"type":504,"tag":522,"props":1134,"children":1135},{},[1136],{"type":510,"value":1137},"Server Components 获取的数据",{"type":510,"value":1139},"：优先走 Next 缓存体系（并建立 revalidate 策略）",{"type":504,"tag":566,"props":1141,"children":1142},{},[1143,1148],{"type":504,"tag":522,"props":1144,"children":1145},{},[1146],{"type":510,"value":1147},"Client Components 交互数据",{"type":510,"value":1149},"（筛选\u002F无限滚动\u002F局部刷新）：用 TanStack Query",{"type":504,"tag":516,"props":1151,"children":1152},{},[1153],{"type":510,"value":1154},"不要让同一数据域同时由两套缓存系统“各自为政”。",{"type":504,"tag":550,"props":1156,"children":1158},{"id":1157},"_7-失效粒度写出既正确又不浪费的-invalidate",[1159],{"type":510,"value":1160},"7. 失效粒度：写出“既正确又不浪费”的 invalidate",{"type":504,"tag":614,"props":1162,"children":1164},{"id":1163},"_71-最小原则只-invalidates-受影响的域",[1165],{"type":510,"value":1166},"7.1 最小原则：只 invalidates 受影响的域",{"type":504,"tag":562,"props":1168,"children":1169},{},[1170,1181],{"type":504,"tag":566,"props":1171,"children":1172},{},[1173,1175],{"type":510,"value":1174},"新增一条评论 → invalidate ",{"type":504,"tag":626,"props":1176,"children":1178},{"className":1177},[],[1179],{"type":510,"value":1180},"['comments', postId]",{"type":504,"tag":566,"props":1182,"children":1183},{},[1184,1186,1192,1194],{"type":510,"value":1185},"修改用户资料 → invalidate ",{"type":504,"tag":626,"props":1187,"children":1189},{"className":1188},[],[1190],{"type":510,"value":1191},"['user', userId]",{"type":510,"value":1193},"，以及可能依赖它的 ",{"type":504,"tag":626,"props":1195,"children":1197},{"className":1196},[],[1198],{"type":510,"value":1199},"['me']",{"type":504,"tag":614,"props":1201,"children":1203},{"id":1202},"_72-常见误区",[1204],{"type":510,"value":1205},"7.2 常见误区",{"type":504,"tag":562,"props":1207,"children":1208},{},[1209,1222],{"type":504,"tag":566,"props":1210,"children":1211},{},[1212,1214,1220],{"type":510,"value":1213},"直接 ",{"type":504,"tag":626,"props":1215,"children":1217},{"className":1216},[],[1218],{"type":510,"value":1219},"invalidateQueries()",{"type":510,"value":1221}," 全清：简单但会造成请求风暴与性能抖动",{"type":504,"tag":566,"props":1223,"children":1224},{},[1225],{"type":510,"value":1226},"key 设计不稳定（对象引用不稳定）：导致命中率低",{"type":504,"tag":550,"props":1228,"children":1230},{"id":1229},"_8-企业级建议统一-queryclient-配置-统一上报",[1231],{"type":510,"value":1232},"8. 企业级建议：统一 QueryClient 配置 + 统一上报",{"type":504,"tag":614,"props":1234,"children":1236},{"id":1235},"_81-queryclient-统一配置示意",[1237],{"type":510,"value":1238},"8.1 QueryClient 统一配置（示意）",{"type":504,"tag":1240,"props":1241,"children":1246},"pre",{"className":1242,"code":1243,"language":1244,"meta":1245,"style":1245},"language-ts shiki shiki-themes github-light github-dark","import { QueryClient } from '@tanstack\u002Freact-query'\n\nexport const queryClient = new QueryClient({\n  defaultOptions: {\n    queries: {\n      staleTime: 30_000,\n      gcTime: 5 * 60_000,\n      retry: 1,\n      refetchOnWindowFocus: false,\n    },\n  },\n})\n","ts","",[1247],{"type":504,"tag":626,"props":1248,"children":1249},{"__ignoreMap":1245},[1250,1279,1288,1329,1338,1347,1366,1394,1412,1430,1439,1448],{"type":504,"tag":1251,"props":1252,"children":1255},"span",{"class":1253,"line":1254},"line",1,[1256,1262,1268,1273],{"type":504,"tag":1251,"props":1257,"children":1259},{"style":1258},"--shiki-default:#D73A49;--shiki-dark:#F97583",[1260],{"type":510,"value":1261},"import",{"type":504,"tag":1251,"props":1263,"children":1265},{"style":1264},"--shiki-default:#24292E;--shiki-dark:#E1E4E8",[1266],{"type":510,"value":1267}," { QueryClient } ",{"type":504,"tag":1251,"props":1269,"children":1270},{"style":1258},[1271],{"type":510,"value":1272},"from",{"type":504,"tag":1251,"props":1274,"children":1276},{"style":1275},"--shiki-default:#032F62;--shiki-dark:#9ECBFF",[1277],{"type":510,"value":1278}," '@tanstack\u002Freact-query'\n",{"type":504,"tag":1251,"props":1280,"children":1281},{"class":1253,"line":906},[1282],{"type":504,"tag":1251,"props":1283,"children":1285},{"emptyLinePlaceholder":1284},true,[1286],{"type":510,"value":1287},"\n",{"type":504,"tag":1251,"props":1289,"children":1291},{"class":1253,"line":1290},3,[1292,1297,1302,1308,1313,1318,1324],{"type":504,"tag":1251,"props":1293,"children":1294},{"style":1258},[1295],{"type":510,"value":1296},"export",{"type":504,"tag":1251,"props":1298,"children":1299},{"style":1258},[1300],{"type":510,"value":1301}," const",{"type":504,"tag":1251,"props":1303,"children":1305},{"style":1304},"--shiki-default:#005CC5;--shiki-dark:#79B8FF",[1306],{"type":510,"value":1307}," queryClient",{"type":504,"tag":1251,"props":1309,"children":1310},{"style":1258},[1311],{"type":510,"value":1312}," =",{"type":504,"tag":1251,"props":1314,"children":1315},{"style":1258},[1316],{"type":510,"value":1317}," new",{"type":504,"tag":1251,"props":1319,"children":1321},{"style":1320},"--shiki-default:#6F42C1;--shiki-dark:#B392F0",[1322],{"type":510,"value":1323}," QueryClient",{"type":504,"tag":1251,"props":1325,"children":1326},{"style":1264},[1327],{"type":510,"value":1328},"({\n",{"type":504,"tag":1251,"props":1330,"children":1332},{"class":1253,"line":1331},4,[1333],{"type":504,"tag":1251,"props":1334,"children":1335},{"style":1264},[1336],{"type":510,"value":1337},"  defaultOptions: {\n",{"type":504,"tag":1251,"props":1339,"children":1341},{"class":1253,"line":1340},5,[1342],{"type":504,"tag":1251,"props":1343,"children":1344},{"style":1264},[1345],{"type":510,"value":1346},"    queries: {\n",{"type":504,"tag":1251,"props":1348,"children":1350},{"class":1253,"line":1349},6,[1351,1356,1361],{"type":504,"tag":1251,"props":1352,"children":1353},{"style":1264},[1354],{"type":510,"value":1355},"      staleTime: ",{"type":504,"tag":1251,"props":1357,"children":1358},{"style":1304},[1359],{"type":510,"value":1360},"30_000",{"type":504,"tag":1251,"props":1362,"children":1363},{"style":1264},[1364],{"type":510,"value":1365},",\n",{"type":504,"tag":1251,"props":1367,"children":1369},{"class":1253,"line":1368},7,[1370,1375,1380,1385,1390],{"type":504,"tag":1251,"props":1371,"children":1372},{"style":1264},[1373],{"type":510,"value":1374},"      gcTime: ",{"type":504,"tag":1251,"props":1376,"children":1377},{"style":1304},[1378],{"type":510,"value":1379},"5",{"type":504,"tag":1251,"props":1381,"children":1382},{"style":1258},[1383],{"type":510,"value":1384}," *",{"type":504,"tag":1251,"props":1386,"children":1387},{"style":1304},[1388],{"type":510,"value":1389}," 60_000",{"type":504,"tag":1251,"props":1391,"children":1392},{"style":1264},[1393],{"type":510,"value":1365},{"type":504,"tag":1251,"props":1395,"children":1397},{"class":1253,"line":1396},8,[1398,1403,1408],{"type":504,"tag":1251,"props":1399,"children":1400},{"style":1264},[1401],{"type":510,"value":1402},"      retry: ",{"type":504,"tag":1251,"props":1404,"children":1405},{"style":1304},[1406],{"type":510,"value":1407},"1",{"type":504,"tag":1251,"props":1409,"children":1410},{"style":1264},[1411],{"type":510,"value":1365},{"type":504,"tag":1251,"props":1413,"children":1415},{"class":1253,"line":1414},9,[1416,1421,1426],{"type":504,"tag":1251,"props":1417,"children":1418},{"style":1264},[1419],{"type":510,"value":1420},"      refetchOnWindowFocus: ",{"type":504,"tag":1251,"props":1422,"children":1423},{"style":1304},[1424],{"type":510,"value":1425},"false",{"type":504,"tag":1251,"props":1427,"children":1428},{"style":1264},[1429],{"type":510,"value":1365},{"type":504,"tag":1251,"props":1431,"children":1433},{"class":1253,"line":1432},10,[1434],{"type":504,"tag":1251,"props":1435,"children":1436},{"style":1264},[1437],{"type":510,"value":1438},"    },\n",{"type":504,"tag":1251,"props":1440,"children":1442},{"class":1253,"line":1441},11,[1443],{"type":504,"tag":1251,"props":1444,"children":1445},{"style":1264},[1446],{"type":510,"value":1447},"  },\n",{"type":504,"tag":1251,"props":1449,"children":1451},{"class":1253,"line":1450},12,[1452],{"type":504,"tag":1251,"props":1453,"children":1454},{"style":1264},[1455],{"type":510,"value":1456},"})\n",{"type":504,"tag":614,"props":1458,"children":1460},{"id":1459},"_82-可观测请求错误与重试要可追踪",[1461],{"type":510,"value":1462},"8.2 可观测：请求错误与重试要可追踪",{"type":504,"tag":516,"props":1464,"children":1465},{},[1466],{"type":510,"value":1467},"建议在请求层做：",{"type":504,"tag":562,"props":1469,"children":1470},{},[1471,1476,1481],{"type":504,"tag":566,"props":1472,"children":1473},{},[1474],{"type":510,"value":1475},"traceId",{"type":504,"tag":566,"props":1477,"children":1478},{},[1479],{"type":510,"value":1480},"统一错误码",{"type":504,"tag":566,"props":1482,"children":1483},{},[1484],{"type":510,"value":1485},"与 Sentry\u002F自研上报打通（尤其是 query error 的聚合与告警）",{"type":504,"tag":550,"props":1487,"children":1489},{"id":1488},"_9-checklist",[1490],{"type":510,"value":1491},"9. Checklist",{"type":504,"tag":562,"props":1493,"children":1496},{"className":1494},[1495],"contains-task-list",[1497,1509,1518,1527,1536],{"type":504,"tag":566,"props":1498,"children":1501},{"className":1499},[1500],"task-list-item",[1502,1507],{"type":504,"tag":1503,"props":1504,"children":1506},"input",{"disabled":1284,"type":1505},"checkbox",[],{"type":510,"value":1508}," queryKey 是否只包含“决定结果”的输入？是否稳定、可序列化？",{"type":504,"tag":566,"props":1510,"children":1512},{"className":1511},[1500],[1513,1516],{"type":504,"tag":1503,"props":1514,"children":1515},{"disabled":1284,"type":1505},[],{"type":510,"value":1517}," URL state 是否作为查询条件的 source of truth？",{"type":504,"tag":566,"props":1519,"children":1521},{"className":1520},[1500],[1522,1525],{"type":504,"tag":1503,"props":1523,"children":1524},{"disabled":1284,"type":1505},[],{"type":510,"value":1526}," mutation 后是否有清晰的 invalidate 规则（粒度合适）？",{"type":504,"tag":566,"props":1528,"children":1530},{"className":1529},[1500],[1531,1534],{"type":504,"tag":1503,"props":1532,"children":1533},{"disabled":1284,"type":1505},[],{"type":510,"value":1535}," staleTime\u002FgcTime 是否符合业务一致性与体验预期？",{"type":504,"tag":566,"props":1537,"children":1539},{"className":1538},[1500],[1540,1543],{"type":504,"tag":1503,"props":1541,"children":1542},{"disabled":1284,"type":1505},[],{"type":510,"value":1544}," 是否避免同一数据域被 Next 缓存与 Query 缓存双重管理？",{"type":504,"tag":550,"props":1546,"children":1548},{"id":1547},"关联阅读",[1549],{"type":510,"value":1547},{"type":504,"tag":562,"props":1551,"children":1552},{},[1553,1568,1582],{"type":504,"tag":566,"props":1554,"children":1555},{},[1556,1558],{"type":510,"value":1557},"状态分层：",{"type":504,"tag":1559,"props":1560,"children":1562},"a",{"href":1561},".\u002F01-state-layering-ui-server-url-global.md",[1563],{"type":504,"tag":626,"props":1564,"children":1566},{"className":1565},[],[1567],{"type":510,"value":1561},{"type":504,"tag":566,"props":1569,"children":1570},{},[1571,1573],{"type":510,"value":1572},"Suspense 与加载态边界：",{"type":504,"tag":1559,"props":1574,"children":1576},{"href":1575},"..\u002F09-react-18-in-practice\u002F04-suspense-loading-boundary-design.md",[1577],{"type":504,"tag":626,"props":1578,"children":1580},{"className":1579},[],[1581],{"type":510,"value":1575},{"type":504,"tag":566,"props":1583,"children":1584},{},[1585,1587],{"type":510,"value":1586},"路由章节（URL state 的承载层）：",{"type":504,"tag":1559,"props":1588,"children":1590},{"href":1589},"..\u002F10-routing-and-navigation\u002FREADME.md",[1591],{"type":504,"tag":626,"props":1592,"children":1594},{"className":1593},[],[1595],{"type":510,"value":1589},{"type":504,"tag":1597,"props":1598,"children":1599},"style",{},[1600],{"type":510,"value":1601},"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":1245,"searchDepth":906,"depth":906,"links":1603},[1604,1605,1609,1613,1618,1619,1620,1624,1628,1632,1633],{"id":552,"depth":906,"text":555},{"id":609,"depth":906,"text":612,"children":1606},[1607,1608],{"id":616,"depth":1290,"text":619},{"id":689,"depth":1290,"text":692},{"id":705,"depth":906,"text":708,"children":1610},[1611,1612],{"id":711,"depth":1290,"text":714},{"id":759,"depth":1290,"text":762},{"id":804,"depth":906,"text":807,"children":1614},[1615,1616,1617],{"id":810,"depth":1290,"text":813},{"id":842,"depth":1290,"text":845},{"id":873,"depth":1290,"text":876},{"id":948,"depth":906,"text":951},{"id":1000,"depth":906,"text":1003},{"id":1052,"depth":906,"text":1055,"children":1621},[1622,1623],{"id":1058,"depth":1290,"text":1061},{"id":1100,"depth":1290,"text":1103},{"id":1157,"depth":906,"text":1160,"children":1625},[1626,1627],{"id":1163,"depth":1290,"text":1166},{"id":1202,"depth":1290,"text":1205},{"id":1229,"depth":906,"text":1232,"children":1629},[1630,1631],{"id":1235,"depth":1290,"text":1238},{"id":1459,"depth":1290,"text":1462},{"id":1488,"depth":906,"text":1491},{"id":1547,"depth":906,"text":1547},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1635},"\u003Cpath fill=\"currentColor\" d=\"m10.828 12l4.95 4.95l-1.414 1.415L8 12l6.364-6.364l1.414 1.414z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1637},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm0 7h12v2H3zm0 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1639},"\u003Cpath fill=\"currentColor\" d=\"m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z\"\u002F>",{"left":4,"top":4,"width":1641,"height":1641,"rotate":4,"vFlip":6,"hFlip":6,"body":1642},1024,"\u003Cpath fill=\"currentColor\" d=\"M768 832a128 128 0 0 1-128 128H192A128 128 0 0 1 64 832V384a128 128 0 0 1 128-128v64a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64z\"\u002F>\u003Cpath fill=\"currentColor\" d=\"M384 128a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64V192a64 64 0 0 0-64-64zm0-64h448a128 128 0 0 1 128 128v448a128 128 0 0 1-128 128H384a128 128 0 0 1-128-128V192A128 128 0 0 1 384 64\"\u002F>"]