[{"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-09-react-18-in-practice\u002F05-error-boundary-reporting-and-recovery":494,"i-ri:arrow-left-s-line":3235,"i-ri:menu-2-line":3237,"i-ri:arrow-right-s-line":3239,"i-ep:copy-document":3241},{"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":359,"path":359,"title":360,"updatedAt":21,"meta":498,"body":500,"toc":3208},"bm90ZTpub3Rlcy9yZWFjdC8wOS1yZWFjdC0xOC1pbi1wcmFjdGljZS8wNS1lcnJvci1ib3VuZGFyeS1yZXBvcnRpbmctYW5kLXJlY292ZXJ5Lm1k","note","notes\u002Freact\u002F09-react-18-in-practice\u002F05-error-boundary-reporting-and-recovery.md",{"id":495,"type":496,"sourcePath":497,"slug":499,"title":360,"updatedAt":21,"lastUpdated":21},"react\u002F09-react-18-in-practice\u002F05-error-boundary-reporting-and-recovery",{"type":501,"children":502},"root",[503,511,543,550,557,562,582,587,593,605,628,633,671,677,682,721,726,739,745,768,773,805,810,823,829,835,869,875,888,894,905,918,924,1473,1478,1503,1509,1515,1578,1584,1589,1602,1607,1615,1767,1783,1934,1942,1958,1963,1984,1990,1995,2002,2145,2151,2614,2620,2751,2757,2780,2788,2794,2799,2812,2817,2992,3005,3011,3017,3050,3056,3080,3086,3148,3153,3202],{"type":504,"tag":505,"props":506,"children":508},"element","h1",{"id":507},"error-boundary兜底重试与上报自研-vs-sentry机制架构视角",[509],{"type":510,"value":360},"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,536,541],{"type":510,"value":520},"一句话结论：Error Boundary 负责处理 React 渲染链路上的“",{"type":504,"tag":522,"props":523,"children":524},"strong",{},[525],{"type":510,"value":526},"同步异常",{"type":510,"value":528},"”（render\u002F生命周期\u002F构造函数等）——当子树抛错时，React 会在最近的 Error Boundary 处",{"type":504,"tag":522,"props":530,"children":531},{},[532],{"type":510,"value":533},"中止该子树的提交",{"type":510,"value":535},"并渲染 fallback；真正的工程落地关键在于：",{"type":504,"tag":522,"props":537,"children":538},{},[539],{"type":510,"value":540},"边界如何分层、如何 reset\u002Fretry、以及错误上报体系（自研或 Sentry）如何做到版本关联、去重、采样、隐私与可观测闭环",{"type":510,"value":542},"。",{"type":504,"tag":544,"props":545,"children":547},"h2",{"id":546},"_1-error-boundary-能捕获什么不能捕获什么必须先讲清",[548],{"type":510,"value":549},"1. Error Boundary 能捕获什么？不能捕获什么？（必须先讲清）",{"type":504,"tag":551,"props":552,"children":554},"h3",{"id":553},"_11-能捕获react-渲染链路的同步错误",[555],{"type":510,"value":556},"1.1 能捕获（React 渲染链路的同步错误）",{"type":504,"tag":516,"props":558,"children":559},{},[560],{"type":510,"value":561},"通常包括：",{"type":504,"tag":563,"props":564,"children":565},"ul",{},[566,572,577],{"type":504,"tag":567,"props":568,"children":569},"li",{},[570],{"type":510,"value":571},"render 阶段抛错（函数组件执行、class render）",{"type":504,"tag":567,"props":573,"children":574},{},[575],{"type":510,"value":576},"生命周期抛错（class 组件的生命周期）",{"type":504,"tag":567,"props":578,"children":579},{},[580],{"type":510,"value":581},"子组件构造函数抛错（class 组件）",{"type":504,"tag":516,"props":583,"children":584},{},[585],{"type":510,"value":586},"当这些错误发生时，React 会沿 Fiber 向上寻找最近的 Error Boundary。",{"type":504,"tag":551,"props":588,"children":590},{"id":589},"_12-不能捕获最常见误区",[591],{"type":510,"value":592},"1.2 不能捕获（最常见误区）",{"type":504,"tag":516,"props":594,"children":595},{},[596,598,603],{"type":510,"value":597},"Error Boundary ",{"type":504,"tag":522,"props":599,"children":600},{},[601],{"type":510,"value":602},"捕获不到",{"type":510,"value":604},"：",{"type":504,"tag":563,"props":606,"children":607},{},[608,613,618,623],{"type":504,"tag":567,"props":609,"children":610},{},[611],{"type":510,"value":612},"事件回调里的错误（onClick\u002FonChange 内 throw）",{"type":504,"tag":567,"props":614,"children":615},{},[616],{"type":510,"value":617},"异步回调里的错误（setTimeout \u002F promise 链 \u002F async\u002Fawait 中 throw）",{"type":504,"tag":567,"props":619,"children":620},{},[621],{"type":510,"value":622},"自定义事件\u002F订阅回调里的错误（WebSocket message、RxJS subscribe 等）",{"type":504,"tag":567,"props":624,"children":625},{},[626],{"type":510,"value":627},"SSR 服务端执行时抛出的错误（这属于服务端错误处理体系）",{"type":504,"tag":516,"props":629,"children":630},{},[631],{"type":510,"value":632},"这些错误需要靠：",{"type":504,"tag":563,"props":634,"children":635},{},[636,641,661,666],{"type":504,"tag":567,"props":637,"children":638},{},[639],{"type":510,"value":640},"try\u002Fcatch（业务层）",{"type":504,"tag":567,"props":642,"children":643},{},[644,651,653,659],{"type":504,"tag":645,"props":646,"children":648},"code",{"className":647},[],[649],{"type":510,"value":650},"window.onerror",{"type":510,"value":652}," \u002F ",{"type":504,"tag":645,"props":654,"children":656},{"className":655},[],[657],{"type":510,"value":658},"unhandledrejection",{"type":510,"value":660},"（全局兜底）",{"type":504,"tag":567,"props":662,"children":663},{},[664],{"type":510,"value":665},"统一请求层\u002F订阅层的错误处理",{"type":504,"tag":567,"props":667,"children":668},{},[669],{"type":510,"value":670},"服务端日志与 tracing",{"type":504,"tag":544,"props":672,"children":674},{"id":673},"_2-机制react-在出错时做了什么",[675],{"type":510,"value":676},"2. 机制：React 在出错时做了什么？",{"type":504,"tag":516,"props":678,"children":679},{},[680],{"type":510,"value":681},"把它放到你已有的 Fiber 认知里更好理解：",{"type":504,"tag":563,"props":683,"children":684},{},[685,690,695],{"type":504,"tag":567,"props":686,"children":687},{},[688],{"type":510,"value":689},"render 阶段：构建 workInProgress 树，可能会执行到某个组件并抛错",{"type":504,"tag":567,"props":691,"children":692},{},[693],{"type":510,"value":694},"React 捕获到错误后，会尝试找到最近的 Error Boundary（本质上是一个带特定能力的祖先 Fiber）",{"type":504,"tag":567,"props":696,"children":697},{},[698,700],{"type":510,"value":699},"一旦找到边界：\n",{"type":504,"tag":563,"props":701,"children":702},{},[703,708,716],{"type":504,"tag":567,"props":704,"children":705},{},[706],{"type":510,"value":707},"React 会把该边界标记为需要处理错误（可理解为“在这个边界处降级”）",{"type":504,"tag":567,"props":709,"children":710},{},[711],{"type":504,"tag":522,"props":712,"children":713},{},[714],{"type":510,"value":715},"丢弃出错子树的本次渲染结果",{"type":504,"tag":567,"props":717,"children":718},{},[719],{"type":510,"value":720},"在 commit 时，渲染边界的 fallback UI（而不是把错误子树提交到 DOM）",{"type":504,"tag":516,"props":722,"children":723},{},[724],{"type":510,"value":725},"这个过程体现了 React 的核心边界：",{"type":504,"tag":563,"props":727,"children":728},{},[729,734],{"type":504,"tag":567,"props":730,"children":731},{},[732],{"type":510,"value":733},"render 可以失败、可以丢弃",{"type":504,"tag":567,"props":735,"children":736},{},[737],{"type":510,"value":738},"commit 要么成功提交一棵一致的 UI，要么回退到 fallback",{"type":504,"tag":544,"props":740,"children":742},{"id":741},"_3-error-boundary-与-suspense一个处理错一个处理等",[743],{"type":510,"value":744},"3. Error Boundary 与 Suspense：一个处理“错”，一个处理“等”",{"type":504,"tag":563,"props":746,"children":747},{},[748,758],{"type":504,"tag":567,"props":749,"children":750},{},[751,756],{"type":504,"tag":522,"props":752,"children":753},{},[754],{"type":510,"value":755},"Suspense",{"type":510,"value":757}," 处理的是 pending（等待）：suspend → fallback（loading）",{"type":504,"tag":567,"props":759,"children":760},{},[761,766],{"type":504,"tag":522,"props":762,"children":763},{},[764],{"type":510,"value":765},"Error Boundary",{"type":510,"value":767}," 处理的是 error（异常）：throw error → fallback（error UI）",{"type":504,"tag":516,"props":769,"children":770},{},[771],{"type":510,"value":772},"架构上建议把两者分治：",{"type":504,"tag":563,"props":774,"children":775},{},[776],{"type":504,"tag":567,"props":777,"children":778},{},[779,781],{"type":510,"value":780},"同一区域既可能“等”也可能“错”时，通常是：\n",{"type":504,"tag":563,"props":782,"children":783},{},[784,795],{"type":504,"tag":567,"props":785,"children":786},{},[787,789],{"type":510,"value":788},"外层 ",{"type":504,"tag":645,"props":790,"children":792},{"className":791},[],[793],{"type":510,"value":794},"ErrorBoundary",{"type":504,"tag":567,"props":796,"children":797},{},[798,800],{"type":510,"value":799},"内层 ",{"type":504,"tag":645,"props":801,"children":803},{"className":802},[],[804],{"type":510,"value":755},{"type":504,"tag":516,"props":806,"children":807},{},[808],{"type":510,"value":809},"这样：",{"type":504,"tag":563,"props":811,"children":812},{},[813,818],{"type":504,"tag":567,"props":814,"children":815},{},[816],{"type":510,"value":817},"加载失败不会被 loading UI 吞掉",{"type":504,"tag":567,"props":819,"children":820},{},[821],{"type":510,"value":822},"错误 UI 不会和 loading 状态混在一起",{"type":504,"tag":544,"props":824,"children":826},{"id":825},"_4-边界怎么切错误兜底的分层策略p0",[827],{"type":510,"value":828},"4. “边界怎么切”：错误兜底的分层策略（P0）",{"type":504,"tag":551,"props":830,"children":832},{"id":831},"_41-三层边界推荐",[833],{"type":510,"value":834},"4.1 三层边界（推荐）",{"type":504,"tag":836,"props":837,"children":838},"ol",{},[839,849,859],{"type":504,"tag":567,"props":840,"children":841},{},[842,847],{"type":504,"tag":522,"props":843,"children":844},{},[845],{"type":510,"value":846},"App-level（全局）",{"type":510,"value":848},"：兜底最后一道防线（避免白屏）",{"type":504,"tag":567,"props":850,"children":851},{},[852,857],{"type":504,"tag":522,"props":853,"children":854},{},[855],{"type":510,"value":856},"Route-level（页面级）",{"type":510,"value":858},"：页面可降级但壳不崩（导航\u002F菜单稳定）",{"type":504,"tag":567,"props":860,"children":861},{},[862,867],{"type":504,"tag":522,"props":863,"children":864},{},[865],{"type":510,"value":866},"Section-level（模块级）",{"type":510,"value":868},"：列表\u002F详情\u002F评论等局部失败不影响整体",{"type":504,"tag":551,"props":870,"children":872},{"id":871},"_42-反例",[873],{"type":510,"value":874},"4.2 反例",{"type":504,"tag":563,"props":876,"children":877},{},[878,883],{"type":504,"tag":567,"props":879,"children":880},{},[881],{"type":510,"value":882},"只有一个全局边界：任何小错误都导致整页错误页（体验差）",{"type":504,"tag":567,"props":884,"children":885},{},[886],{"type":510,"value":887},"过度碎片化：上报量暴增、fallback 频繁闪烁、用户迷惑",{"type":504,"tag":544,"props":889,"children":891},{"id":890},"_5-recovery如何重试恢复resetkeys-onreset",[892],{"type":510,"value":893},"5. Recovery：如何“重试\u002F恢复”（resetKeys \u002F onReset）",{"type":504,"tag":516,"props":895,"children":896},{},[897,899,904],{"type":510,"value":898},"一个好的错误兜底不只是展示错误信息，更关键是",{"type":504,"tag":522,"props":900,"children":901},{},[902],{"type":510,"value":903},"能恢复",{"type":510,"value":604},{"type":504,"tag":563,"props":906,"children":907},{},[908,913],{"type":504,"tag":567,"props":909,"children":910},{},[911],{"type":510,"value":912},"用户点“重试”",{"type":504,"tag":567,"props":914,"children":915},{},[916],{"type":510,"value":917},"或者路由变化\u002F参数变化时自动 reset",{"type":504,"tag":551,"props":919,"children":921},{"id":920},"_51-使用-react-error-boundary推荐的工程化方式",[922],{"type":510,"value":923},"5.1 使用 react-error-boundary（推荐的工程化方式）",{"type":504,"tag":925,"props":926,"children":931},"pre",{"className":927,"code":928,"language":929,"meta":930,"style":930},"language-tsx shiki shiki-themes github-light github-dark","import { ErrorBoundary } from 'react-error-boundary'\n\nfunction ErrorFallback({ error, resetErrorBoundary }: any) {\n  return (\n    \u003Cdiv>\n      \u003Cp>模块加载失败：{String(error?.message ?? error)}\u003C\u002Fp>\n      \u003Cbutton onClick={resetErrorBoundary}>重试\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  )\n}\n\nexport function Section() {\n  const queryKey = 'users:list'\n\n  return (\n    \u003CErrorBoundary\n      FallbackComponent={ErrorFallback}\n      resetKeys={[queryKey]}\n      onReset={() => {\n        \u002F\u002F 清缓存\u002F重拉数据等\n      }}\n      onError={(error, info) => {\n        \u002F\u002F 上报（见下文）\n      }}\n    >\n      \u003CUsersList \u002F>\n    \u003C\u002FErrorBoundary>\n  )\n}\n","tsx","",[932],{"type":504,"tag":645,"props":933,"children":934},{"__ignoreMap":930},[935,964,974,1031,1045,1065,1111,1147,1164,1173,1182,1190,1214,1238,1246,1258,1271,1289,1307,1335,1345,1354,1398,1407,1414,1423,1441,1457,1465],{"type":504,"tag":936,"props":937,"children":940},"span",{"class":938,"line":939},"line",1,[941,947,953,958],{"type":504,"tag":936,"props":942,"children":944},{"style":943},"--shiki-default:#D73A49;--shiki-dark:#F97583",[945],{"type":510,"value":946},"import",{"type":504,"tag":936,"props":948,"children":950},{"style":949},"--shiki-default:#24292E;--shiki-dark:#E1E4E8",[951],{"type":510,"value":952}," { ErrorBoundary } ",{"type":504,"tag":936,"props":954,"children":955},{"style":943},[956],{"type":510,"value":957},"from",{"type":504,"tag":936,"props":959,"children":961},{"style":960},"--shiki-default:#032F62;--shiki-dark:#9ECBFF",[962],{"type":510,"value":963}," 'react-error-boundary'\n",{"type":504,"tag":936,"props":965,"children":967},{"class":938,"line":966},2,[968],{"type":504,"tag":936,"props":969,"children":971},{"emptyLinePlaceholder":970},true,[972],{"type":510,"value":973},"\n",{"type":504,"tag":936,"props":975,"children":977},{"class":938,"line":976},3,[978,983,989,994,1000,1005,1010,1015,1020,1026],{"type":504,"tag":936,"props":979,"children":980},{"style":943},[981],{"type":510,"value":982},"function",{"type":504,"tag":936,"props":984,"children":986},{"style":985},"--shiki-default:#6F42C1;--shiki-dark:#B392F0",[987],{"type":510,"value":988}," ErrorFallback",{"type":504,"tag":936,"props":990,"children":991},{"style":949},[992],{"type":510,"value":993},"({ ",{"type":504,"tag":936,"props":995,"children":997},{"style":996},"--shiki-default:#E36209;--shiki-dark:#FFAB70",[998],{"type":510,"value":999},"error",{"type":504,"tag":936,"props":1001,"children":1002},{"style":949},[1003],{"type":510,"value":1004},", ",{"type":504,"tag":936,"props":1006,"children":1007},{"style":996},[1008],{"type":510,"value":1009},"resetErrorBoundary",{"type":504,"tag":936,"props":1011,"children":1012},{"style":949},[1013],{"type":510,"value":1014}," }",{"type":504,"tag":936,"props":1016,"children":1017},{"style":943},[1018],{"type":510,"value":1019},":",{"type":504,"tag":936,"props":1021,"children":1023},{"style":1022},"--shiki-default:#005CC5;--shiki-dark:#79B8FF",[1024],{"type":510,"value":1025}," any",{"type":504,"tag":936,"props":1027,"children":1028},{"style":949},[1029],{"type":510,"value":1030},") {\n",{"type":504,"tag":936,"props":1032,"children":1034},{"class":938,"line":1033},4,[1035,1040],{"type":504,"tag":936,"props":1036,"children":1037},{"style":943},[1038],{"type":510,"value":1039},"  return",{"type":504,"tag":936,"props":1041,"children":1042},{"style":949},[1043],{"type":510,"value":1044}," (\n",{"type":504,"tag":936,"props":1046,"children":1048},{"class":938,"line":1047},5,[1049,1054,1060],{"type":504,"tag":936,"props":1050,"children":1051},{"style":949},[1052],{"type":510,"value":1053},"    \u003C",{"type":504,"tag":936,"props":1055,"children":1057},{"style":1056},"--shiki-default:#22863A;--shiki-dark:#85E89D",[1058],{"type":510,"value":1059},"div",{"type":504,"tag":936,"props":1061,"children":1062},{"style":949},[1063],{"type":510,"value":1064},">\n",{"type":504,"tag":936,"props":1066,"children":1068},{"class":938,"line":1067},6,[1069,1074,1078,1083,1088,1093,1098,1103,1107],{"type":504,"tag":936,"props":1070,"children":1071},{"style":949},[1072],{"type":510,"value":1073},"      \u003C",{"type":504,"tag":936,"props":1075,"children":1076},{"style":1056},[1077],{"type":510,"value":516},{"type":504,"tag":936,"props":1079,"children":1080},{"style":949},[1081],{"type":510,"value":1082},">模块加载失败：{",{"type":504,"tag":936,"props":1084,"children":1085},{"style":985},[1086],{"type":510,"value":1087},"String",{"type":504,"tag":936,"props":1089,"children":1090},{"style":949},[1091],{"type":510,"value":1092},"(error?.message ",{"type":504,"tag":936,"props":1094,"children":1095},{"style":943},[1096],{"type":510,"value":1097},"??",{"type":504,"tag":936,"props":1099,"children":1100},{"style":949},[1101],{"type":510,"value":1102}," error)}\u003C\u002F",{"type":504,"tag":936,"props":1104,"children":1105},{"style":1056},[1106],{"type":510,"value":516},{"type":504,"tag":936,"props":1108,"children":1109},{"style":949},[1110],{"type":510,"value":1064},{"type":504,"tag":936,"props":1112,"children":1114},{"class":938,"line":1113},7,[1115,1119,1124,1129,1134,1139,1143],{"type":504,"tag":936,"props":1116,"children":1117},{"style":949},[1118],{"type":510,"value":1073},{"type":504,"tag":936,"props":1120,"children":1121},{"style":1056},[1122],{"type":510,"value":1123},"button",{"type":504,"tag":936,"props":1125,"children":1126},{"style":985},[1127],{"type":510,"value":1128}," onClick",{"type":504,"tag":936,"props":1130,"children":1131},{"style":943},[1132],{"type":510,"value":1133},"=",{"type":504,"tag":936,"props":1135,"children":1136},{"style":949},[1137],{"type":510,"value":1138},"{resetErrorBoundary}>重试\u003C\u002F",{"type":504,"tag":936,"props":1140,"children":1141},{"style":1056},[1142],{"type":510,"value":1123},{"type":504,"tag":936,"props":1144,"children":1145},{"style":949},[1146],{"type":510,"value":1064},{"type":504,"tag":936,"props":1148,"children":1150},{"class":938,"line":1149},8,[1151,1156,1160],{"type":504,"tag":936,"props":1152,"children":1153},{"style":949},[1154],{"type":510,"value":1155},"    \u003C\u002F",{"type":504,"tag":936,"props":1157,"children":1158},{"style":1056},[1159],{"type":510,"value":1059},{"type":504,"tag":936,"props":1161,"children":1162},{"style":949},[1163],{"type":510,"value":1064},{"type":504,"tag":936,"props":1165,"children":1167},{"class":938,"line":1166},9,[1168],{"type":504,"tag":936,"props":1169,"children":1170},{"style":949},[1171],{"type":510,"value":1172},"  )\n",{"type":504,"tag":936,"props":1174,"children":1176},{"class":938,"line":1175},10,[1177],{"type":504,"tag":936,"props":1178,"children":1179},{"style":949},[1180],{"type":510,"value":1181},"}\n",{"type":504,"tag":936,"props":1183,"children":1185},{"class":938,"line":1184},11,[1186],{"type":504,"tag":936,"props":1187,"children":1188},{"emptyLinePlaceholder":970},[1189],{"type":510,"value":973},{"type":504,"tag":936,"props":1191,"children":1193},{"class":938,"line":1192},12,[1194,1199,1204,1209],{"type":504,"tag":936,"props":1195,"children":1196},{"style":943},[1197],{"type":510,"value":1198},"export",{"type":504,"tag":936,"props":1200,"children":1201},{"style":943},[1202],{"type":510,"value":1203}," function",{"type":504,"tag":936,"props":1205,"children":1206},{"style":985},[1207],{"type":510,"value":1208}," Section",{"type":504,"tag":936,"props":1210,"children":1211},{"style":949},[1212],{"type":510,"value":1213},"() {\n",{"type":504,"tag":936,"props":1215,"children":1217},{"class":938,"line":1216},13,[1218,1223,1228,1233],{"type":504,"tag":936,"props":1219,"children":1220},{"style":943},[1221],{"type":510,"value":1222},"  const",{"type":504,"tag":936,"props":1224,"children":1225},{"style":1022},[1226],{"type":510,"value":1227}," queryKey",{"type":504,"tag":936,"props":1229,"children":1230},{"style":943},[1231],{"type":510,"value":1232}," =",{"type":504,"tag":936,"props":1234,"children":1235},{"style":960},[1236],{"type":510,"value":1237}," 'users:list'\n",{"type":504,"tag":936,"props":1239,"children":1241},{"class":938,"line":1240},14,[1242],{"type":504,"tag":936,"props":1243,"children":1244},{"emptyLinePlaceholder":970},[1245],{"type":510,"value":973},{"type":504,"tag":936,"props":1247,"children":1249},{"class":938,"line":1248},15,[1250,1254],{"type":504,"tag":936,"props":1251,"children":1252},{"style":943},[1253],{"type":510,"value":1039},{"type":504,"tag":936,"props":1255,"children":1256},{"style":949},[1257],{"type":510,"value":1044},{"type":504,"tag":936,"props":1259,"children":1261},{"class":938,"line":1260},16,[1262,1266],{"type":504,"tag":936,"props":1263,"children":1264},{"style":949},[1265],{"type":510,"value":1053},{"type":504,"tag":936,"props":1267,"children":1268},{"style":1022},[1269],{"type":510,"value":1270},"ErrorBoundary\n",{"type":504,"tag":936,"props":1272,"children":1274},{"class":938,"line":1273},17,[1275,1280,1284],{"type":504,"tag":936,"props":1276,"children":1277},{"style":985},[1278],{"type":510,"value":1279},"      FallbackComponent",{"type":504,"tag":936,"props":1281,"children":1282},{"style":943},[1283],{"type":510,"value":1133},{"type":504,"tag":936,"props":1285,"children":1286},{"style":949},[1287],{"type":510,"value":1288},"{ErrorFallback}\n",{"type":504,"tag":936,"props":1290,"children":1292},{"class":938,"line":1291},18,[1293,1298,1302],{"type":504,"tag":936,"props":1294,"children":1295},{"style":985},[1296],{"type":510,"value":1297},"      resetKeys",{"type":504,"tag":936,"props":1299,"children":1300},{"style":943},[1301],{"type":510,"value":1133},{"type":504,"tag":936,"props":1303,"children":1304},{"style":949},[1305],{"type":510,"value":1306},"{[queryKey]}\n",{"type":504,"tag":936,"props":1308,"children":1310},{"class":938,"line":1309},19,[1311,1316,1320,1325,1330],{"type":504,"tag":936,"props":1312,"children":1313},{"style":985},[1314],{"type":510,"value":1315},"      onReset",{"type":504,"tag":936,"props":1317,"children":1318},{"style":943},[1319],{"type":510,"value":1133},{"type":504,"tag":936,"props":1321,"children":1322},{"style":949},[1323],{"type":510,"value":1324},"{() ",{"type":504,"tag":936,"props":1326,"children":1327},{"style":943},[1328],{"type":510,"value":1329},"=>",{"type":504,"tag":936,"props":1331,"children":1332},{"style":949},[1333],{"type":510,"value":1334}," {\n",{"type":504,"tag":936,"props":1336,"children":1338},{"class":938,"line":1337},20,[1339],{"type":504,"tag":936,"props":1340,"children":1342},{"style":1341},"--shiki-default:#6A737D;--shiki-dark:#6A737D",[1343],{"type":510,"value":1344},"        \u002F\u002F 清缓存\u002F重拉数据等\n",{"type":504,"tag":936,"props":1346,"children":1348},{"class":938,"line":1347},21,[1349],{"type":504,"tag":936,"props":1350,"children":1351},{"style":949},[1352],{"type":510,"value":1353},"      }}\n",{"type":504,"tag":936,"props":1355,"children":1357},{"class":938,"line":1356},22,[1358,1363,1367,1372,1376,1380,1385,1390,1394],{"type":504,"tag":936,"props":1359,"children":1360},{"style":985},[1361],{"type":510,"value":1362},"      onError",{"type":504,"tag":936,"props":1364,"children":1365},{"style":943},[1366],{"type":510,"value":1133},{"type":504,"tag":936,"props":1368,"children":1369},{"style":949},[1370],{"type":510,"value":1371},"{(",{"type":504,"tag":936,"props":1373,"children":1374},{"style":996},[1375],{"type":510,"value":999},{"type":504,"tag":936,"props":1377,"children":1378},{"style":949},[1379],{"type":510,"value":1004},{"type":504,"tag":936,"props":1381,"children":1382},{"style":996},[1383],{"type":510,"value":1384},"info",{"type":504,"tag":936,"props":1386,"children":1387},{"style":949},[1388],{"type":510,"value":1389},") ",{"type":504,"tag":936,"props":1391,"children":1392},{"style":943},[1393],{"type":510,"value":1329},{"type":504,"tag":936,"props":1395,"children":1396},{"style":949},[1397],{"type":510,"value":1334},{"type":504,"tag":936,"props":1399,"children":1401},{"class":938,"line":1400},23,[1402],{"type":504,"tag":936,"props":1403,"children":1404},{"style":1341},[1405],{"type":510,"value":1406},"        \u002F\u002F 上报（见下文）\n",{"type":504,"tag":936,"props":1408,"children":1409},{"class":938,"line":5},[1410],{"type":504,"tag":936,"props":1411,"children":1412},{"style":949},[1413],{"type":510,"value":1353},{"type":504,"tag":936,"props":1415,"children":1417},{"class":938,"line":1416},25,[1418],{"type":504,"tag":936,"props":1419,"children":1420},{"style":949},[1421],{"type":510,"value":1422},"    >\n",{"type":504,"tag":936,"props":1424,"children":1426},{"class":938,"line":1425},26,[1427,1431,1436],{"type":504,"tag":936,"props":1428,"children":1429},{"style":949},[1430],{"type":510,"value":1073},{"type":504,"tag":936,"props":1432,"children":1433},{"style":1022},[1434],{"type":510,"value":1435},"UsersList",{"type":504,"tag":936,"props":1437,"children":1438},{"style":949},[1439],{"type":510,"value":1440}," \u002F>\n",{"type":504,"tag":936,"props":1442,"children":1444},{"class":938,"line":1443},27,[1445,1449,1453],{"type":504,"tag":936,"props":1446,"children":1447},{"style":949},[1448],{"type":510,"value":1155},{"type":504,"tag":936,"props":1450,"children":1451},{"style":1022},[1452],{"type":510,"value":794},{"type":504,"tag":936,"props":1454,"children":1455},{"style":949},[1456],{"type":510,"value":1064},{"type":504,"tag":936,"props":1458,"children":1460},{"class":938,"line":1459},28,[1461],{"type":504,"tag":936,"props":1462,"children":1463},{"style":949},[1464],{"type":510,"value":1172},{"type":504,"tag":936,"props":1466,"children":1468},{"class":938,"line":1467},29,[1469],{"type":504,"tag":936,"props":1470,"children":1471},{"style":949},[1472],{"type":510,"value":1181},{"type":504,"tag":516,"props":1474,"children":1475},{},[1476],{"type":510,"value":1477},"要点：",{"type":504,"tag":563,"props":1479,"children":1480},{},[1481,1492],{"type":504,"tag":567,"props":1482,"children":1483},{},[1484,1490],{"type":504,"tag":645,"props":1485,"children":1487},{"className":1486},[],[1488],{"type":510,"value":1489},"resetKeys",{"type":510,"value":1491}," 让边界在关键输入变化时自动恢复",{"type":504,"tag":567,"props":1493,"children":1494},{},[1495,1501],{"type":504,"tag":645,"props":1496,"children":1498},{"className":1497},[],[1499],{"type":510,"value":1500},"onReset",{"type":510,"value":1502}," 做“恢复动作”（清缓存、invalidate query、reset store）",{"type":504,"tag":544,"props":1504,"children":1506},{"id":1505},"_6-上报体系自研-vs-sentry适配不同企业策略",[1507],{"type":510,"value":1508},"6. 上报体系：自研 vs Sentry（适配不同企业策略）",{"type":504,"tag":551,"props":1510,"children":1512},{"id":1511},"_61-共同目标无论自研还是-sentry-都要做到",[1513],{"type":510,"value":1514},"6.1 共同目标（无论自研还是 Sentry 都要做到）",{"type":504,"tag":563,"props":1516,"children":1517},{},[1518,1528,1538,1548,1558,1568],{"type":504,"tag":567,"props":1519,"children":1520},{},[1521,1526],{"type":504,"tag":522,"props":1522,"children":1523},{},[1524],{"type":510,"value":1525},"版本关联",{"type":510,"value":1527},"：release \u002F commit \u002F buildId",{"type":504,"tag":567,"props":1529,"children":1530},{},[1531,1536],{"type":504,"tag":522,"props":1532,"children":1533},{},[1534],{"type":510,"value":1535},"去重聚合",{"type":510,"value":1537},"：按 stack + message + route 聚合",{"type":504,"tag":567,"props":1539,"children":1540},{},[1541,1546],{"type":504,"tag":522,"props":1542,"children":1543},{},[1544],{"type":510,"value":1545},"采样与限流",{"type":510,"value":1547},"：避免错误风暴打爆后端",{"type":504,"tag":567,"props":1549,"children":1550},{},[1551,1556],{"type":504,"tag":522,"props":1552,"children":1553},{},[1554],{"type":510,"value":1555},"上下文",{"type":510,"value":1557},"：用户\u002F租户\u002F路由\u002Ffeature flag\u002F网络状态",{"type":504,"tag":567,"props":1559,"children":1560},{},[1561,1566],{"type":504,"tag":522,"props":1562,"children":1563},{},[1564],{"type":510,"value":1565},"SourceMap",{"type":510,"value":1567},"：线上堆栈可还原（注意安全策略）",{"type":504,"tag":567,"props":1569,"children":1570},{},[1571,1576],{"type":504,"tag":522,"props":1572,"children":1573},{},[1574],{"type":510,"value":1575},"隐私合规",{"type":510,"value":1577},"：PII 脱敏、字段白名单",{"type":504,"tag":551,"props":1579,"children":1581},{"id":1580},"_62-方案-a接入-sentry开箱即用适合效率优先",[1582],{"type":510,"value":1583},"6.2 方案 A：接入 Sentry（开箱即用，适合效率优先）",{"type":504,"tag":516,"props":1585,"children":1586},{},[1587],{"type":510,"value":1588},"优点：",{"type":504,"tag":563,"props":1590,"children":1591},{},[1592,1597],{"type":504,"tag":567,"props":1593,"children":1594},{},[1595],{"type":510,"value":1596},"聚合、告警、趋势、Release、SourceMap、性能\u002FTracing 能力成熟",{"type":504,"tag":567,"props":1598,"children":1599},{},[1600],{"type":510,"value":1601},"生态完善，React 集成很顺",{"type":504,"tag":516,"props":1603,"children":1604},{},[1605],{"type":510,"value":1606},"关键落地点：",{"type":504,"tag":836,"props":1608,"children":1609},{},[1610],{"type":504,"tag":567,"props":1611,"children":1612},{},[1613],{"type":510,"value":1614},"初始化与 release",{"type":504,"tag":925,"props":1616,"children":1620},{"className":1617,"code":1618,"language":1619,"meta":930,"style":930},"language-ts shiki shiki-themes github-light github-dark","import * as Sentry from '@sentry\u002Freact'\n\nSentry.init({\n  dsn: process.env.SENTRY_DSN,\n  release: process.env.APP_RELEASE, \u002F\u002F commit hash 或版本号\n  environment: process.env.APP_ENV,\n  tracesSampleRate: 0.0, \u002F\u002F 需要再开\n})\n","ts",[1621],{"type":504,"tag":645,"props":1622,"children":1623},{"__ignoreMap":930},[1624,1655,1662,1680,1698,1720,1737,1759],{"type":504,"tag":936,"props":1625,"children":1626},{"class":938,"line":939},[1627,1631,1636,1641,1646,1650],{"type":504,"tag":936,"props":1628,"children":1629},{"style":943},[1630],{"type":510,"value":946},{"type":504,"tag":936,"props":1632,"children":1633},{"style":1022},[1634],{"type":510,"value":1635}," *",{"type":504,"tag":936,"props":1637,"children":1638},{"style":943},[1639],{"type":510,"value":1640}," as",{"type":504,"tag":936,"props":1642,"children":1643},{"style":949},[1644],{"type":510,"value":1645}," Sentry ",{"type":504,"tag":936,"props":1647,"children":1648},{"style":943},[1649],{"type":510,"value":957},{"type":504,"tag":936,"props":1651,"children":1652},{"style":960},[1653],{"type":510,"value":1654}," '@sentry\u002Freact'\n",{"type":504,"tag":936,"props":1656,"children":1657},{"class":938,"line":966},[1658],{"type":504,"tag":936,"props":1659,"children":1660},{"emptyLinePlaceholder":970},[1661],{"type":510,"value":973},{"type":504,"tag":936,"props":1663,"children":1664},{"class":938,"line":976},[1665,1670,1675],{"type":504,"tag":936,"props":1666,"children":1667},{"style":949},[1668],{"type":510,"value":1669},"Sentry.",{"type":504,"tag":936,"props":1671,"children":1672},{"style":985},[1673],{"type":510,"value":1674},"init",{"type":504,"tag":936,"props":1676,"children":1677},{"style":949},[1678],{"type":510,"value":1679},"({\n",{"type":504,"tag":936,"props":1681,"children":1682},{"class":938,"line":1033},[1683,1688,1693],{"type":504,"tag":936,"props":1684,"children":1685},{"style":949},[1686],{"type":510,"value":1687},"  dsn: process.env.",{"type":504,"tag":936,"props":1689,"children":1690},{"style":1022},[1691],{"type":510,"value":1692},"SENTRY_DSN",{"type":504,"tag":936,"props":1694,"children":1695},{"style":949},[1696],{"type":510,"value":1697},",\n",{"type":504,"tag":936,"props":1699,"children":1700},{"class":938,"line":1047},[1701,1706,1711,1715],{"type":504,"tag":936,"props":1702,"children":1703},{"style":949},[1704],{"type":510,"value":1705},"  release: process.env.",{"type":504,"tag":936,"props":1707,"children":1708},{"style":1022},[1709],{"type":510,"value":1710},"APP_RELEASE",{"type":504,"tag":936,"props":1712,"children":1713},{"style":949},[1714],{"type":510,"value":1004},{"type":504,"tag":936,"props":1716,"children":1717},{"style":1341},[1718],{"type":510,"value":1719},"\u002F\u002F commit hash 或版本号\n",{"type":504,"tag":936,"props":1721,"children":1722},{"class":938,"line":1067},[1723,1728,1733],{"type":504,"tag":936,"props":1724,"children":1725},{"style":949},[1726],{"type":510,"value":1727},"  environment: process.env.",{"type":504,"tag":936,"props":1729,"children":1730},{"style":1022},[1731],{"type":510,"value":1732},"APP_ENV",{"type":504,"tag":936,"props":1734,"children":1735},{"style":949},[1736],{"type":510,"value":1697},{"type":504,"tag":936,"props":1738,"children":1739},{"class":938,"line":1113},[1740,1745,1750,1754],{"type":504,"tag":936,"props":1741,"children":1742},{"style":949},[1743],{"type":510,"value":1744},"  tracesSampleRate: ",{"type":504,"tag":936,"props":1746,"children":1747},{"style":1022},[1748],{"type":510,"value":1749},"0.0",{"type":504,"tag":936,"props":1751,"children":1752},{"style":949},[1753],{"type":510,"value":1004},{"type":504,"tag":936,"props":1755,"children":1756},{"style":1341},[1757],{"type":510,"value":1758},"\u002F\u002F 需要再开\n",{"type":504,"tag":936,"props":1760,"children":1761},{"class":938,"line":1149},[1762],{"type":504,"tag":936,"props":1763,"children":1764},{"style":949},[1765],{"type":510,"value":1766},"})\n",{"type":504,"tag":836,"props":1768,"children":1769},{"start":966},[1770],{"type":504,"tag":567,"props":1771,"children":1772},{},[1773,1775,1781],{"type":510,"value":1774},"在 Error Boundary 的 ",{"type":504,"tag":645,"props":1776,"children":1778},{"className":1777},[],[1779],{"type":510,"value":1780},"onError",{"type":510,"value":1782}," 中 capture",{"type":504,"tag":925,"props":1784,"children":1786},{"className":1617,"code":1785,"language":1619,"meta":930,"style":930},"onError={(error, info) => {\n  Sentry.withScope(scope => {\n    scope.setTag('boundary', 'users-section')\n    scope.setContext('react', { componentStack: info?.componentStack })\n    Sentry.captureException(error)\n  })\n}}\n",[1787],{"type":504,"tag":645,"props":1788,"children":1789},{"__ignoreMap":930},[1790,1806,1838,1874,1900,1918,1926],{"type":504,"tag":936,"props":1791,"children":1792},{"class":938,"line":939},[1793,1797,1801],{"type":504,"tag":936,"props":1794,"children":1795},{"style":949},[1796],{"type":510,"value":1780},{"type":504,"tag":936,"props":1798,"children":1799},{"style":943},[1800],{"type":510,"value":1133},{"type":504,"tag":936,"props":1802,"children":1803},{"style":949},[1804],{"type":510,"value":1805},"{(error, info) => {\n",{"type":504,"tag":936,"props":1807,"children":1808},{"class":938,"line":966},[1809,1814,1819,1824,1829,1834],{"type":504,"tag":936,"props":1810,"children":1811},{"style":949},[1812],{"type":510,"value":1813},"  Sentry.",{"type":504,"tag":936,"props":1815,"children":1816},{"style":985},[1817],{"type":510,"value":1818},"withScope",{"type":504,"tag":936,"props":1820,"children":1821},{"style":949},[1822],{"type":510,"value":1823},"(",{"type":504,"tag":936,"props":1825,"children":1826},{"style":996},[1827],{"type":510,"value":1828},"scope",{"type":504,"tag":936,"props":1830,"children":1831},{"style":943},[1832],{"type":510,"value":1833}," =>",{"type":504,"tag":936,"props":1835,"children":1836},{"style":949},[1837],{"type":510,"value":1334},{"type":504,"tag":936,"props":1839,"children":1840},{"class":938,"line":976},[1841,1846,1851,1855,1860,1864,1869],{"type":504,"tag":936,"props":1842,"children":1843},{"style":949},[1844],{"type":510,"value":1845},"    scope.",{"type":504,"tag":936,"props":1847,"children":1848},{"style":985},[1849],{"type":510,"value":1850},"setTag",{"type":504,"tag":936,"props":1852,"children":1853},{"style":949},[1854],{"type":510,"value":1823},{"type":504,"tag":936,"props":1856,"children":1857},{"style":960},[1858],{"type":510,"value":1859},"'boundary'",{"type":504,"tag":936,"props":1861,"children":1862},{"style":949},[1863],{"type":510,"value":1004},{"type":504,"tag":936,"props":1865,"children":1866},{"style":960},[1867],{"type":510,"value":1868},"'users-section'",{"type":504,"tag":936,"props":1870,"children":1871},{"style":949},[1872],{"type":510,"value":1873},")\n",{"type":504,"tag":936,"props":1875,"children":1876},{"class":938,"line":1033},[1877,1881,1886,1890,1895],{"type":504,"tag":936,"props":1878,"children":1879},{"style":949},[1880],{"type":510,"value":1845},{"type":504,"tag":936,"props":1882,"children":1883},{"style":985},[1884],{"type":510,"value":1885},"setContext",{"type":504,"tag":936,"props":1887,"children":1888},{"style":949},[1889],{"type":510,"value":1823},{"type":504,"tag":936,"props":1891,"children":1892},{"style":960},[1893],{"type":510,"value":1894},"'react'",{"type":504,"tag":936,"props":1896,"children":1897},{"style":949},[1898],{"type":510,"value":1899},", { componentStack: info?.componentStack })\n",{"type":504,"tag":936,"props":1901,"children":1902},{"class":938,"line":1047},[1903,1908,1913],{"type":504,"tag":936,"props":1904,"children":1905},{"style":949},[1906],{"type":510,"value":1907},"    Sentry.",{"type":504,"tag":936,"props":1909,"children":1910},{"style":985},[1911],{"type":510,"value":1912},"captureException",{"type":504,"tag":936,"props":1914,"children":1915},{"style":949},[1916],{"type":510,"value":1917},"(error)\n",{"type":504,"tag":936,"props":1919,"children":1920},{"class":938,"line":1067},[1921],{"type":504,"tag":936,"props":1922,"children":1923},{"style":949},[1924],{"type":510,"value":1925},"  })\n",{"type":504,"tag":936,"props":1927,"children":1928},{"class":938,"line":1113},[1929],{"type":504,"tag":936,"props":1930,"children":1931},{"style":949},[1932],{"type":510,"value":1933},"}}\n",{"type":504,"tag":836,"props":1935,"children":1936},{"start":976},[1937],{"type":504,"tag":567,"props":1938,"children":1939},{},[1940],{"type":510,"value":1941},"事件回调\u002F异步错误",{"type":504,"tag":563,"props":1943,"children":1944},{},[1945],{"type":504,"tag":567,"props":1946,"children":1947},{},[1948,1950,1956],{"type":510,"value":1949},"Sentry 通常也能通过全局 hook 捕获 ",{"type":504,"tag":645,"props":1951,"children":1953},{"className":1952},[],[1954],{"type":510,"value":1955},"window.onerror \u002F unhandledrejection",{"type":510,"value":1957},"，但你仍建议在关键异步链路里显式捕获并补充上下文。",{"type":504,"tag":516,"props":1959,"children":1960},{},[1961],{"type":510,"value":1962},"适配建议：",{"type":504,"tag":563,"props":1964,"children":1965},{},[1966],{"type":504,"tag":567,"props":1967,"children":1968},{},[1969,1971,1976,1978,1983],{"type":510,"value":1970},"大多数团队采用：",{"type":504,"tag":522,"props":1972,"children":1973},{},[1974],{"type":510,"value":1975},"Sentry 做主链路",{"type":510,"value":1977}," + ",{"type":504,"tag":522,"props":1979,"children":1980},{},[1981],{"type":510,"value":1982},"自研做补充（业务字段\u002F审计）",{"type":510,"value":542},{"type":504,"tag":551,"props":1985,"children":1987},{"id":1986},"_63-方案-b自研上报可控适合合规私有化成本敏感",[1988],{"type":510,"value":1989},"6.3 方案 B：自研上报（可控、适合合规\u002F私有化\u002F成本敏感）",{"type":504,"tag":516,"props":1991,"children":1992},{},[1993],{"type":510,"value":1994},"自研的核心不是“发一个请求”，而是要做“可运营的错误平台”的最小闭环。",{"type":504,"tag":1996,"props":1997,"children":1999},"h4",{"id":1998},"_631-事件模型建议",[2000],{"type":510,"value":2001},"6.3.1 事件模型（建议）",{"type":504,"tag":563,"props":2003,"children":2004},{},[2005,2014,2023,2034,2057,2073,2082,2093,2111,2134],{"type":504,"tag":567,"props":2006,"children":2007},{},[2008],{"type":504,"tag":645,"props":2009,"children":2011},{"className":2010},[],[2012],{"type":510,"value":2013},"eventId",{"type":504,"tag":567,"props":2015,"children":2016},{},[2017],{"type":504,"tag":645,"props":2018,"children":2020},{"className":2019},[],[2021],{"type":510,"value":2022},"timestamp",{"type":504,"tag":567,"props":2024,"children":2025},{},[2026,2032],{"type":504,"tag":645,"props":2027,"children":2029},{"className":2028},[],[2030],{"type":510,"value":2031},"release",{"type":510,"value":2033},"（版本）",{"type":504,"tag":567,"props":2035,"children":2036},{},[2037,2043,2044,2050,2051],{"type":504,"tag":645,"props":2038,"children":2040},{"className":2039},[],[2041],{"type":510,"value":2042},"route",{"type":510,"value":652},{"type":504,"tag":645,"props":2045,"children":2047},{"className":2046},[],[2048],{"type":510,"value":2049},"pathname",{"type":510,"value":652},{"type":504,"tag":645,"props":2052,"children":2054},{"className":2053},[],[2055],{"type":510,"value":2056},"search",{"type":504,"tag":567,"props":2058,"children":2059},{},[2060,2066,2067],{"type":504,"tag":645,"props":2061,"children":2063},{"className":2062},[],[2064],{"type":510,"value":2065},"errorName",{"type":510,"value":652},{"type":504,"tag":645,"props":2068,"children":2070},{"className":2069},[],[2071],{"type":510,"value":2072},"message",{"type":504,"tag":567,"props":2074,"children":2075},{},[2076],{"type":504,"tag":645,"props":2077,"children":2079},{"className":2078},[],[2080],{"type":510,"value":2081},"stack",{"type":504,"tag":567,"props":2083,"children":2084},{},[2085,2091],{"type":504,"tag":645,"props":2086,"children":2088},{"className":2087},[],[2089],{"type":510,"value":2090},"componentStack",{"type":510,"value":2092},"（Error Boundary 能提供）",{"type":504,"tag":567,"props":2094,"children":2095},{},[2096,2102,2103,2109],{"type":504,"tag":645,"props":2097,"children":2099},{"className":2098},[],[2100],{"type":510,"value":2101},"userId",{"type":510,"value":652},{"type":504,"tag":645,"props":2104,"children":2106},{"className":2105},[],[2107],{"type":510,"value":2108},"tenantId",{"type":510,"value":2110},"（可选，注意脱敏）",{"type":504,"tag":567,"props":2112,"children":2113},{},[2114,2120,2121,2127,2128],{"type":504,"tag":645,"props":2115,"children":2117},{"className":2116},[],[2118],{"type":510,"value":2119},"device",{"type":510,"value":652},{"type":504,"tag":645,"props":2122,"children":2124},{"className":2123},[],[2125],{"type":510,"value":2126},"ua",{"type":510,"value":652},{"type":504,"tag":645,"props":2129,"children":2131},{"className":2130},[],[2132],{"type":510,"value":2133},"network",{"type":504,"tag":567,"props":2135,"children":2136},{},[2137,2143],{"type":504,"tag":645,"props":2138,"children":2140},{"className":2139},[],[2141],{"type":510,"value":2142},"tags",{"type":510,"value":2144},"（feature \u002F boundary \u002F module）",{"type":504,"tag":1996,"props":2146,"children":2148},{"id":2147},"_632-客户端-sdk最小实现",[2149],{"type":510,"value":2150},"6.3.2 客户端 SDK（最小实现）",{"type":504,"tag":925,"props":2152,"children":2154},{"className":1617,"code":2153,"language":1619,"meta":930,"style":930},"type ReportPayload = {\n  release: string\n  message: string\n  stack?: string\n  componentStack?: string\n  route?: string\n  tags?: Record\u003Cstring, string>\n}\n\nexport async function reportError(payload: ReportPayload) {\n  \u002F\u002F 去重\u002F采样（示意）\n  const sampled = Math.random() \u003C 0.1\n  if (!sampled) return\n\n  navigator.sendBeacon?.('\u002Fapi\u002Ffe-error', JSON.stringify(payload))\n    ?? fetch('\u002Fapi\u002Ffe-error', {\n      method: 'POST',\n      headers: { 'content-type': 'application\u002Fjson' },\n      body: JSON.stringify(payload),\n      keepalive: true,\n    })\n}\n",[2155],{"type":504,"tag":645,"props":2156,"children":2157},{"__ignoreMap":930},[2158,2179,2196,2212,2229,2245,2261,2300,2307,2314,2356,2364,2404,2432,2439,2486,2512,2529,2557,2582,2599,2607],{"type":504,"tag":936,"props":2159,"children":2160},{"class":938,"line":939},[2161,2166,2171,2175],{"type":504,"tag":936,"props":2162,"children":2163},{"style":943},[2164],{"type":510,"value":2165},"type",{"type":504,"tag":936,"props":2167,"children":2168},{"style":985},[2169],{"type":510,"value":2170}," ReportPayload",{"type":504,"tag":936,"props":2172,"children":2173},{"style":943},[2174],{"type":510,"value":1232},{"type":504,"tag":936,"props":2176,"children":2177},{"style":949},[2178],{"type":510,"value":1334},{"type":504,"tag":936,"props":2180,"children":2181},{"class":938,"line":966},[2182,2187,2191],{"type":504,"tag":936,"props":2183,"children":2184},{"style":996},[2185],{"type":510,"value":2186},"  release",{"type":504,"tag":936,"props":2188,"children":2189},{"style":943},[2190],{"type":510,"value":1019},{"type":504,"tag":936,"props":2192,"children":2193},{"style":1022},[2194],{"type":510,"value":2195}," string\n",{"type":504,"tag":936,"props":2197,"children":2198},{"class":938,"line":976},[2199,2204,2208],{"type":504,"tag":936,"props":2200,"children":2201},{"style":996},[2202],{"type":510,"value":2203},"  message",{"type":504,"tag":936,"props":2205,"children":2206},{"style":943},[2207],{"type":510,"value":1019},{"type":504,"tag":936,"props":2209,"children":2210},{"style":1022},[2211],{"type":510,"value":2195},{"type":504,"tag":936,"props":2213,"children":2214},{"class":938,"line":1033},[2215,2220,2225],{"type":504,"tag":936,"props":2216,"children":2217},{"style":996},[2218],{"type":510,"value":2219},"  stack",{"type":504,"tag":936,"props":2221,"children":2222},{"style":943},[2223],{"type":510,"value":2224},"?:",{"type":504,"tag":936,"props":2226,"children":2227},{"style":1022},[2228],{"type":510,"value":2195},{"type":504,"tag":936,"props":2230,"children":2231},{"class":938,"line":1047},[2232,2237,2241],{"type":504,"tag":936,"props":2233,"children":2234},{"style":996},[2235],{"type":510,"value":2236},"  componentStack",{"type":504,"tag":936,"props":2238,"children":2239},{"style":943},[2240],{"type":510,"value":2224},{"type":504,"tag":936,"props":2242,"children":2243},{"style":1022},[2244],{"type":510,"value":2195},{"type":504,"tag":936,"props":2246,"children":2247},{"class":938,"line":1067},[2248,2253,2257],{"type":504,"tag":936,"props":2249,"children":2250},{"style":996},[2251],{"type":510,"value":2252},"  route",{"type":504,"tag":936,"props":2254,"children":2255},{"style":943},[2256],{"type":510,"value":2224},{"type":504,"tag":936,"props":2258,"children":2259},{"style":1022},[2260],{"type":510,"value":2195},{"type":504,"tag":936,"props":2262,"children":2263},{"class":938,"line":1113},[2264,2269,2273,2278,2283,2288,2292,2296],{"type":504,"tag":936,"props":2265,"children":2266},{"style":996},[2267],{"type":510,"value":2268},"  tags",{"type":504,"tag":936,"props":2270,"children":2271},{"style":943},[2272],{"type":510,"value":2224},{"type":504,"tag":936,"props":2274,"children":2275},{"style":985},[2276],{"type":510,"value":2277}," Record",{"type":504,"tag":936,"props":2279,"children":2280},{"style":949},[2281],{"type":510,"value":2282},"\u003C",{"type":504,"tag":936,"props":2284,"children":2285},{"style":1022},[2286],{"type":510,"value":2287},"string",{"type":504,"tag":936,"props":2289,"children":2290},{"style":949},[2291],{"type":510,"value":1004},{"type":504,"tag":936,"props":2293,"children":2294},{"style":1022},[2295],{"type":510,"value":2287},{"type":504,"tag":936,"props":2297,"children":2298},{"style":949},[2299],{"type":510,"value":1064},{"type":504,"tag":936,"props":2301,"children":2302},{"class":938,"line":1149},[2303],{"type":504,"tag":936,"props":2304,"children":2305},{"style":949},[2306],{"type":510,"value":1181},{"type":504,"tag":936,"props":2308,"children":2309},{"class":938,"line":1166},[2310],{"type":504,"tag":936,"props":2311,"children":2312},{"emptyLinePlaceholder":970},[2313],{"type":510,"value":973},{"type":504,"tag":936,"props":2315,"children":2316},{"class":938,"line":1175},[2317,2321,2326,2330,2335,2339,2344,2348,2352],{"type":504,"tag":936,"props":2318,"children":2319},{"style":943},[2320],{"type":510,"value":1198},{"type":504,"tag":936,"props":2322,"children":2323},{"style":943},[2324],{"type":510,"value":2325}," async",{"type":504,"tag":936,"props":2327,"children":2328},{"style":943},[2329],{"type":510,"value":1203},{"type":504,"tag":936,"props":2331,"children":2332},{"style":985},[2333],{"type":510,"value":2334}," reportError",{"type":504,"tag":936,"props":2336,"children":2337},{"style":949},[2338],{"type":510,"value":1823},{"type":504,"tag":936,"props":2340,"children":2341},{"style":996},[2342],{"type":510,"value":2343},"payload",{"type":504,"tag":936,"props":2345,"children":2346},{"style":943},[2347],{"type":510,"value":1019},{"type":504,"tag":936,"props":2349,"children":2350},{"style":985},[2351],{"type":510,"value":2170},{"type":504,"tag":936,"props":2353,"children":2354},{"style":949},[2355],{"type":510,"value":1030},{"type":504,"tag":936,"props":2357,"children":2358},{"class":938,"line":1184},[2359],{"type":504,"tag":936,"props":2360,"children":2361},{"style":1341},[2362],{"type":510,"value":2363},"  \u002F\u002F 去重\u002F采样（示意）\n",{"type":504,"tag":936,"props":2365,"children":2366},{"class":938,"line":1192},[2367,2371,2376,2380,2385,2390,2395,2399],{"type":504,"tag":936,"props":2368,"children":2369},{"style":943},[2370],{"type":510,"value":1222},{"type":504,"tag":936,"props":2372,"children":2373},{"style":1022},[2374],{"type":510,"value":2375}," sampled",{"type":504,"tag":936,"props":2377,"children":2378},{"style":943},[2379],{"type":510,"value":1232},{"type":504,"tag":936,"props":2381,"children":2382},{"style":949},[2383],{"type":510,"value":2384}," Math.",{"type":504,"tag":936,"props":2386,"children":2387},{"style":985},[2388],{"type":510,"value":2389},"random",{"type":504,"tag":936,"props":2391,"children":2392},{"style":949},[2393],{"type":510,"value":2394},"() ",{"type":504,"tag":936,"props":2396,"children":2397},{"style":943},[2398],{"type":510,"value":2282},{"type":504,"tag":936,"props":2400,"children":2401},{"style":1022},[2402],{"type":510,"value":2403}," 0.1\n",{"type":504,"tag":936,"props":2405,"children":2406},{"class":938,"line":1216},[2407,2412,2417,2422,2427],{"type":504,"tag":936,"props":2408,"children":2409},{"style":943},[2410],{"type":510,"value":2411},"  if",{"type":504,"tag":936,"props":2413,"children":2414},{"style":949},[2415],{"type":510,"value":2416}," (",{"type":504,"tag":936,"props":2418,"children":2419},{"style":943},[2420],{"type":510,"value":2421},"!",{"type":504,"tag":936,"props":2423,"children":2424},{"style":949},[2425],{"type":510,"value":2426},"sampled) ",{"type":504,"tag":936,"props":2428,"children":2429},{"style":943},[2430],{"type":510,"value":2431},"return\n",{"type":504,"tag":936,"props":2433,"children":2434},{"class":938,"line":1240},[2435],{"type":504,"tag":936,"props":2436,"children":2437},{"emptyLinePlaceholder":970},[2438],{"type":510,"value":973},{"type":504,"tag":936,"props":2440,"children":2441},{"class":938,"line":1248},[2442,2447,2452,2457,2462,2466,2471,2476,2481],{"type":504,"tag":936,"props":2443,"children":2444},{"style":949},[2445],{"type":510,"value":2446},"  navigator.",{"type":504,"tag":936,"props":2448,"children":2449},{"style":985},[2450],{"type":510,"value":2451},"sendBeacon",{"type":504,"tag":936,"props":2453,"children":2454},{"style":949},[2455],{"type":510,"value":2456},"?.(",{"type":504,"tag":936,"props":2458,"children":2459},{"style":960},[2460],{"type":510,"value":2461},"'\u002Fapi\u002Ffe-error'",{"type":504,"tag":936,"props":2463,"children":2464},{"style":949},[2465],{"type":510,"value":1004},{"type":504,"tag":936,"props":2467,"children":2468},{"style":1022},[2469],{"type":510,"value":2470},"JSON",{"type":504,"tag":936,"props":2472,"children":2473},{"style":949},[2474],{"type":510,"value":2475},".",{"type":504,"tag":936,"props":2477,"children":2478},{"style":985},[2479],{"type":510,"value":2480},"stringify",{"type":504,"tag":936,"props":2482,"children":2483},{"style":949},[2484],{"type":510,"value":2485},"(payload))\n",{"type":504,"tag":936,"props":2487,"children":2488},{"class":938,"line":1260},[2489,2494,2499,2503,2507],{"type":504,"tag":936,"props":2490,"children":2491},{"style":943},[2492],{"type":510,"value":2493},"    ??",{"type":504,"tag":936,"props":2495,"children":2496},{"style":985},[2497],{"type":510,"value":2498}," fetch",{"type":504,"tag":936,"props":2500,"children":2501},{"style":949},[2502],{"type":510,"value":1823},{"type":504,"tag":936,"props":2504,"children":2505},{"style":960},[2506],{"type":510,"value":2461},{"type":504,"tag":936,"props":2508,"children":2509},{"style":949},[2510],{"type":510,"value":2511},", {\n",{"type":504,"tag":936,"props":2513,"children":2514},{"class":938,"line":1273},[2515,2520,2525],{"type":504,"tag":936,"props":2516,"children":2517},{"style":949},[2518],{"type":510,"value":2519},"      method: ",{"type":504,"tag":936,"props":2521,"children":2522},{"style":960},[2523],{"type":510,"value":2524},"'POST'",{"type":504,"tag":936,"props":2526,"children":2527},{"style":949},[2528],{"type":510,"value":1697},{"type":504,"tag":936,"props":2530,"children":2531},{"class":938,"line":1291},[2532,2537,2542,2547,2552],{"type":504,"tag":936,"props":2533,"children":2534},{"style":949},[2535],{"type":510,"value":2536},"      headers: { ",{"type":504,"tag":936,"props":2538,"children":2539},{"style":960},[2540],{"type":510,"value":2541},"'content-type'",{"type":504,"tag":936,"props":2543,"children":2544},{"style":949},[2545],{"type":510,"value":2546},": ",{"type":504,"tag":936,"props":2548,"children":2549},{"style":960},[2550],{"type":510,"value":2551},"'application\u002Fjson'",{"type":504,"tag":936,"props":2553,"children":2554},{"style":949},[2555],{"type":510,"value":2556}," },\n",{"type":504,"tag":936,"props":2558,"children":2559},{"class":938,"line":1309},[2560,2565,2569,2573,2577],{"type":504,"tag":936,"props":2561,"children":2562},{"style":949},[2563],{"type":510,"value":2564},"      body: ",{"type":504,"tag":936,"props":2566,"children":2567},{"style":1022},[2568],{"type":510,"value":2470},{"type":504,"tag":936,"props":2570,"children":2571},{"style":949},[2572],{"type":510,"value":2475},{"type":504,"tag":936,"props":2574,"children":2575},{"style":985},[2576],{"type":510,"value":2480},{"type":504,"tag":936,"props":2578,"children":2579},{"style":949},[2580],{"type":510,"value":2581},"(payload),\n",{"type":504,"tag":936,"props":2583,"children":2584},{"class":938,"line":1337},[2585,2590,2595],{"type":504,"tag":936,"props":2586,"children":2587},{"style":949},[2588],{"type":510,"value":2589},"      keepalive: ",{"type":504,"tag":936,"props":2591,"children":2592},{"style":1022},[2593],{"type":510,"value":2594},"true",{"type":504,"tag":936,"props":2596,"children":2597},{"style":949},[2598],{"type":510,"value":1697},{"type":504,"tag":936,"props":2600,"children":2601},{"class":938,"line":1347},[2602],{"type":504,"tag":936,"props":2603,"children":2604},{"style":949},[2605],{"type":510,"value":2606},"    })\n",{"type":504,"tag":936,"props":2608,"children":2609},{"class":938,"line":1356},[2610],{"type":504,"tag":936,"props":2611,"children":2612},{"style":949},[2613],{"type":510,"value":1181},{"type":504,"tag":1996,"props":2615,"children":2617},{"id":2616},"_633-在-error-boundary-中上报",[2618],{"type":510,"value":2619},"6.3.3 在 Error Boundary 中上报",{"type":504,"tag":925,"props":2621,"children":2623},{"className":1617,"code":2622,"language":1619,"meta":930,"style":930},"onError={(error, info) => {\n  reportError({\n    release: __APP_RELEASE__,\n    message: String(error?.message ?? error),\n    stack: error?.stack,\n    componentStack: info?.componentStack,\n    route: location.pathname + location.search,\n    tags: { boundary: 'users-section' },\n  })\n}}\n",[2624],{"type":504,"tag":645,"props":2625,"children":2626},{"__ignoreMap":930},[2627,2642,2654,2662,2687,2695,2703,2721,2737,2744],{"type":504,"tag":936,"props":2628,"children":2629},{"class":938,"line":939},[2630,2634,2638],{"type":504,"tag":936,"props":2631,"children":2632},{"style":949},[2633],{"type":510,"value":1780},{"type":504,"tag":936,"props":2635,"children":2636},{"style":943},[2637],{"type":510,"value":1133},{"type":504,"tag":936,"props":2639,"children":2640},{"style":949},[2641],{"type":510,"value":1805},{"type":504,"tag":936,"props":2643,"children":2644},{"class":938,"line":966},[2645,2650],{"type":504,"tag":936,"props":2646,"children":2647},{"style":985},[2648],{"type":510,"value":2649},"  reportError",{"type":504,"tag":936,"props":2651,"children":2652},{"style":949},[2653],{"type":510,"value":1679},{"type":504,"tag":936,"props":2655,"children":2656},{"class":938,"line":976},[2657],{"type":504,"tag":936,"props":2658,"children":2659},{"style":949},[2660],{"type":510,"value":2661},"    release: __APP_RELEASE__,\n",{"type":504,"tag":936,"props":2663,"children":2664},{"class":938,"line":1033},[2665,2670,2674,2678,2682],{"type":504,"tag":936,"props":2666,"children":2667},{"style":949},[2668],{"type":510,"value":2669},"    message: ",{"type":504,"tag":936,"props":2671,"children":2672},{"style":985},[2673],{"type":510,"value":1087},{"type":504,"tag":936,"props":2675,"children":2676},{"style":949},[2677],{"type":510,"value":1092},{"type":504,"tag":936,"props":2679,"children":2680},{"style":943},[2681],{"type":510,"value":1097},{"type":504,"tag":936,"props":2683,"children":2684},{"style":949},[2685],{"type":510,"value":2686}," error),\n",{"type":504,"tag":936,"props":2688,"children":2689},{"class":938,"line":1047},[2690],{"type":504,"tag":936,"props":2691,"children":2692},{"style":949},[2693],{"type":510,"value":2694},"    stack: error?.stack,\n",{"type":504,"tag":936,"props":2696,"children":2697},{"class":938,"line":1067},[2698],{"type":504,"tag":936,"props":2699,"children":2700},{"style":949},[2701],{"type":510,"value":2702},"    componentStack: info?.componentStack,\n",{"type":504,"tag":936,"props":2704,"children":2705},{"class":938,"line":1113},[2706,2711,2716],{"type":504,"tag":936,"props":2707,"children":2708},{"style":949},[2709],{"type":510,"value":2710},"    route: location.pathname ",{"type":504,"tag":936,"props":2712,"children":2713},{"style":943},[2714],{"type":510,"value":2715},"+",{"type":504,"tag":936,"props":2717,"children":2718},{"style":949},[2719],{"type":510,"value":2720}," location.search,\n",{"type":504,"tag":936,"props":2722,"children":2723},{"class":938,"line":1149},[2724,2729,2733],{"type":504,"tag":936,"props":2725,"children":2726},{"style":949},[2727],{"type":510,"value":2728},"    tags: { boundary: ",{"type":504,"tag":936,"props":2730,"children":2731},{"style":960},[2732],{"type":510,"value":1868},{"type":504,"tag":936,"props":2734,"children":2735},{"style":949},[2736],{"type":510,"value":2556},{"type":504,"tag":936,"props":2738,"children":2739},{"class":938,"line":1166},[2740],{"type":504,"tag":936,"props":2741,"children":2742},{"style":949},[2743],{"type":510,"value":1925},{"type":504,"tag":936,"props":2745,"children":2746},{"class":938,"line":1175},[2747],{"type":504,"tag":936,"props":2748,"children":2749},{"style":949},[2750],{"type":510,"value":1933},{"type":504,"tag":1996,"props":2752,"children":2754},{"id":2753},"_634-服务端接收全栈视角建议",[2755],{"type":510,"value":2756},"6.3.4 服务端接收（全栈视角建议）",{"type":504,"tag":563,"props":2758,"children":2759},{},[2760,2765,2770,2775],{"type":504,"tag":567,"props":2761,"children":2762},{},[2763],{"type":510,"value":2764},"做限流（IP\u002F租户\u002F版本维度）",{"type":504,"tag":567,"props":2766,"children":2767},{},[2768],{"type":510,"value":2769},"做聚合键（stack hash）",{"type":504,"tag":567,"props":2771,"children":2772},{},[2773],{"type":510,"value":2774},"存储：ClickHouse\u002FES\u002FPG 都行（看规模）",{"type":504,"tag":567,"props":2776,"children":2777},{},[2778],{"type":510,"value":2779},"告警：按“版本新增错误”“错误率突增”“关键路径错误”",{"type":504,"tag":512,"props":2781,"children":2782},{},[2783],{"type":504,"tag":516,"props":2784,"children":2785},{},[2786],{"type":510,"value":2787},"自研策略更适合：私有化部署、强合规（不出网）、或希望把错误与业务指标\u002F审计打通的企业。",{"type":504,"tag":551,"props":2789,"children":2791},{"id":2790},"_64-混合策略同一套边界双通道可切换",[2792],{"type":510,"value":2793},"6.4 混合策略：同一套边界，双通道可切换",{"type":504,"tag":516,"props":2795,"children":2796},{},[2797],{"type":510,"value":2798},"很多企业会要求：",{"type":504,"tag":563,"props":2800,"children":2801},{},[2802,2807],{"type":504,"tag":567,"props":2803,"children":2804},{},[2805],{"type":510,"value":2806},"国内\u002F私有化：走自研",{"type":504,"tag":567,"props":2808,"children":2809},{},[2810],{"type":510,"value":2811},"海外\u002F效率优先：走 Sentry",{"type":504,"tag":516,"props":2813,"children":2814},{},[2815],{"type":510,"value":2816},"建议做成“上报适配层”：",{"type":504,"tag":925,"props":2818,"children":2820},{"className":1617,"code":2819,"language":1619,"meta":930,"style":930},"export interface ErrorReporter {\n  capture(error: unknown, ctx: Record\u003Cstring, any>): void\n}\n\nexport const reporter: ErrorReporter = isSentryEnabled\n  ? sentryReporter\n  : selfHostedReporter\n",[2821],{"type":504,"tag":645,"props":2822,"children":2823},{"__ignoreMap":930},[2824,2845,2918,2925,2932,2966,2979],{"type":504,"tag":936,"props":2825,"children":2826},{"class":938,"line":939},[2827,2831,2836,2841],{"type":504,"tag":936,"props":2828,"children":2829},{"style":943},[2830],{"type":510,"value":1198},{"type":504,"tag":936,"props":2832,"children":2833},{"style":943},[2834],{"type":510,"value":2835}," interface",{"type":504,"tag":936,"props":2837,"children":2838},{"style":985},[2839],{"type":510,"value":2840}," ErrorReporter",{"type":504,"tag":936,"props":2842,"children":2843},{"style":949},[2844],{"type":510,"value":1334},{"type":504,"tag":936,"props":2846,"children":2847},{"class":938,"line":966},[2848,2853,2857,2861,2865,2870,2874,2879,2883,2887,2891,2895,2899,2904,2909,2913],{"type":504,"tag":936,"props":2849,"children":2850},{"style":985},[2851],{"type":510,"value":2852},"  capture",{"type":504,"tag":936,"props":2854,"children":2855},{"style":949},[2856],{"type":510,"value":1823},{"type":504,"tag":936,"props":2858,"children":2859},{"style":996},[2860],{"type":510,"value":999},{"type":504,"tag":936,"props":2862,"children":2863},{"style":943},[2864],{"type":510,"value":1019},{"type":504,"tag":936,"props":2866,"children":2867},{"style":1022},[2868],{"type":510,"value":2869}," unknown",{"type":504,"tag":936,"props":2871,"children":2872},{"style":949},[2873],{"type":510,"value":1004},{"type":504,"tag":936,"props":2875,"children":2876},{"style":996},[2877],{"type":510,"value":2878},"ctx",{"type":504,"tag":936,"props":2880,"children":2881},{"style":943},[2882],{"type":510,"value":1019},{"type":504,"tag":936,"props":2884,"children":2885},{"style":985},[2886],{"type":510,"value":2277},{"type":504,"tag":936,"props":2888,"children":2889},{"style":949},[2890],{"type":510,"value":2282},{"type":504,"tag":936,"props":2892,"children":2893},{"style":1022},[2894],{"type":510,"value":2287},{"type":504,"tag":936,"props":2896,"children":2897},{"style":949},[2898],{"type":510,"value":1004},{"type":504,"tag":936,"props":2900,"children":2901},{"style":1022},[2902],{"type":510,"value":2903},"any",{"type":504,"tag":936,"props":2905,"children":2906},{"style":949},[2907],{"type":510,"value":2908},">)",{"type":504,"tag":936,"props":2910,"children":2911},{"style":943},[2912],{"type":510,"value":1019},{"type":504,"tag":936,"props":2914,"children":2915},{"style":1022},[2916],{"type":510,"value":2917}," void\n",{"type":504,"tag":936,"props":2919,"children":2920},{"class":938,"line":976},[2921],{"type":504,"tag":936,"props":2922,"children":2923},{"style":949},[2924],{"type":510,"value":1181},{"type":504,"tag":936,"props":2926,"children":2927},{"class":938,"line":1033},[2928],{"type":504,"tag":936,"props":2929,"children":2930},{"emptyLinePlaceholder":970},[2931],{"type":510,"value":973},{"type":504,"tag":936,"props":2933,"children":2934},{"class":938,"line":1047},[2935,2939,2944,2949,2953,2957,2961],{"type":504,"tag":936,"props":2936,"children":2937},{"style":943},[2938],{"type":510,"value":1198},{"type":504,"tag":936,"props":2940,"children":2941},{"style":943},[2942],{"type":510,"value":2943}," const",{"type":504,"tag":936,"props":2945,"children":2946},{"style":1022},[2947],{"type":510,"value":2948}," reporter",{"type":504,"tag":936,"props":2950,"children":2951},{"style":943},[2952],{"type":510,"value":1019},{"type":504,"tag":936,"props":2954,"children":2955},{"style":985},[2956],{"type":510,"value":2840},{"type":504,"tag":936,"props":2958,"children":2959},{"style":943},[2960],{"type":510,"value":1232},{"type":504,"tag":936,"props":2962,"children":2963},{"style":949},[2964],{"type":510,"value":2965}," isSentryEnabled\n",{"type":504,"tag":936,"props":2967,"children":2968},{"class":938,"line":1067},[2969,2974],{"type":504,"tag":936,"props":2970,"children":2971},{"style":943},[2972],{"type":510,"value":2973},"  ?",{"type":504,"tag":936,"props":2975,"children":2976},{"style":949},[2977],{"type":510,"value":2978}," sentryReporter\n",{"type":504,"tag":936,"props":2980,"children":2981},{"class":938,"line":1113},[2982,2987],{"type":504,"tag":936,"props":2983,"children":2984},{"style":943},[2985],{"type":510,"value":2986},"  :",{"type":504,"tag":936,"props":2988,"children":2989},{"style":949},[2990],{"type":510,"value":2991}," selfHostedReporter\n",{"type":504,"tag":516,"props":2993,"children":2994},{},[2995,2997,3003],{"type":510,"value":2996},"业务侧只依赖 ",{"type":504,"tag":645,"props":2998,"children":3000},{"className":2999},[],[3001],{"type":510,"value":3002},"reporter.capture",{"type":510,"value":3004},"，避免 vendor lock-in 扩散。",{"type":504,"tag":544,"props":3006,"children":3008},{"id":3007},"_7-nextjs-与-tanstack-router-的落地点",[3009],{"type":510,"value":3010},"7. Next.js 与 TanStack Router 的落地点",{"type":504,"tag":551,"props":3012,"children":3014},{"id":3013},"_71-nextjs-app-router",[3015],{"type":510,"value":3016},"7.1 Next.js App Router",{"type":504,"tag":563,"props":3018,"children":3019},{},[3020,3033,3038],{"type":504,"tag":567,"props":3021,"children":3022},{},[3023,3025,3031],{"type":510,"value":3024},"route segment 可以用 ",{"type":504,"tag":645,"props":3026,"children":3028},{"className":3027},[],[3029],{"type":510,"value":3030},"error.tsx",{"type":510,"value":3032}," 做段级错误页",{"type":504,"tag":567,"props":3034,"children":3035},{},[3036],{"type":510,"value":3037},"仍建议在客户端交互密集模块内使用组件级 Error Boundary（更细粒度、更可恢复）",{"type":504,"tag":567,"props":3039,"children":3040},{},[3041,3043,3048],{"type":510,"value":3042},"上报可在 ",{"type":504,"tag":645,"props":3044,"children":3046},{"className":3045},[],[3047],{"type":510,"value":3030},{"type":510,"value":3049}," 内或通过统一 client SDK 完成",{"type":504,"tag":551,"props":3051,"children":3053},{"id":3052},"_72-tanstack-router-vite",[3054],{"type":510,"value":3055},"7.2 TanStack Router + Vite",{"type":504,"tag":563,"props":3057,"children":3058},{},[3059,3064,3069],{"type":504,"tag":567,"props":3060,"children":3061},{},[3062],{"type":510,"value":3063},"路由层可在 route component 外包一层 route-level Error Boundary",{"type":504,"tag":567,"props":3065,"children":3066},{},[3067],{"type":510,"value":3068},"模块层用 section-level Error Boundary",{"type":504,"tag":567,"props":3070,"children":3071},{},[3072,3074],{"type":510,"value":3073},"配合 TanStack Query：错误页的“重试”通常对应 ",{"type":504,"tag":645,"props":3075,"children":3077},{"className":3076},[],[3078],{"type":510,"value":3079},"queryClient.invalidateQueries(...)",{"type":504,"tag":544,"props":3081,"children":3083},{"id":3082},"_8-checklist",[3084],{"type":510,"value":3085},"8. Checklist",{"type":504,"tag":563,"props":3087,"children":3090},{"className":3088},[3089],"contains-task-list",[3091,3103,3112,3121,3130,3139],{"type":504,"tag":567,"props":3092,"children":3095},{"className":3093},[3094],"task-list-item",[3096,3101],{"type":504,"tag":3097,"props":3098,"children":3100},"input",{"disabled":970,"type":3099},"checkbox",[],{"type":510,"value":3102}," 我是否清楚哪些错误 Error Boundary 捕获不到？（事件\u002F异步\u002F订阅）",{"type":504,"tag":567,"props":3104,"children":3106},{"className":3105},[3094],[3107,3110],{"type":504,"tag":3097,"props":3108,"children":3109},{"disabled":970,"type":3099},[],{"type":510,"value":3111}," 边界是否分层（app\u002Froute\u002Fsection），壳是否稳定？",{"type":504,"tag":567,"props":3113,"children":3115},{"className":3114},[3094],[3116,3119],{"type":504,"tag":3097,"props":3117,"children":3118},{"disabled":970,"type":3099},[],{"type":510,"value":3120}," fallback 是否提供恢复路径（重试\u002F返回\u002F刷新），并且 resetKeys 合理？",{"type":504,"tag":567,"props":3122,"children":3124},{"className":3123},[3094],[3125,3128],{"type":504,"tag":3097,"props":3126,"children":3127},{"disabled":970,"type":3099},[],{"type":510,"value":3129}," 上报是否做了 release\u002Fversion 关联与 SourceMap 策略？",{"type":504,"tag":567,"props":3131,"children":3133},{"className":3132},[3094],[3134,3137],{"type":504,"tag":3097,"props":3135,"children":3136},{"disabled":970,"type":3099},[],{"type":510,"value":3138}," 上报是否做了采样\u002F限流\u002F去重，避免错误风暴？",{"type":504,"tag":567,"props":3140,"children":3142},{"className":3141},[3094],[3143,3146],{"type":504,"tag":3097,"props":3144,"children":3145},{"disabled":970,"type":3099},[],{"type":510,"value":3147}," 是否有隐私脱敏策略（PII）？",{"type":504,"tag":544,"props":3149,"children":3151},{"id":3150},"关联阅读",[3152],{"type":510,"value":3150},{"type":504,"tag":563,"props":3154,"children":3155},{},[3156,3172,3187],{"type":504,"tag":567,"props":3157,"children":3158},{},[3159,3161],{"type":510,"value":3160},"Suspense（处理“等”）：",{"type":504,"tag":3162,"props":3163,"children":3165},"a",{"href":3164},".\u002F04-suspense-loading-boundary-design.md",[3166],{"type":504,"tag":645,"props":3167,"children":3169},{"className":3168},[],[3170],{"type":510,"value":3171},"notes\u002F09-react-18-in-practice\u002F04-suspense-loading-boundary-design.md",{"type":504,"tag":567,"props":3173,"children":3174},{},[3175,3177],{"type":510,"value":3176},"StrictMode（暴露副作用问题）：",{"type":504,"tag":3162,"props":3178,"children":3180},{"href":3179},".\u002F02-strictmode-and-idempotent-effects.md",[3181],{"type":504,"tag":645,"props":3182,"children":3184},{"className":3183},[],[3185],{"type":510,"value":3186},"notes\u002F09-react-18-in-practice\u002F02-strictmode-and-idempotent-effects.md",{"type":504,"tag":567,"props":3188,"children":3189},{},[3190,3192],{"type":510,"value":3191},"事件系统（事件回调错误不进边界）：",{"type":504,"tag":3162,"props":3193,"children":3195},{"href":3194},"..\u002F07-event-system\u002F01-overview.md",[3196],{"type":504,"tag":645,"props":3197,"children":3199},{"className":3198},[],[3200],{"type":510,"value":3201},"notes\u002F07-event-system\u002F01-overview.md",{"type":504,"tag":3203,"props":3204,"children":3205},"style",{},[3206],{"type":510,"value":3207},"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":930,"searchDepth":966,"depth":966,"links":3209},[3210,3214,3215,3216,3220,3223,3229,3233,3234],{"id":546,"depth":966,"text":549,"children":3211},[3212,3213],{"id":553,"depth":976,"text":556},{"id":589,"depth":976,"text":592},{"id":673,"depth":966,"text":676},{"id":741,"depth":966,"text":744},{"id":825,"depth":966,"text":828,"children":3217},[3218,3219],{"id":831,"depth":976,"text":834},{"id":871,"depth":976,"text":874},{"id":890,"depth":966,"text":893,"children":3221},[3222],{"id":920,"depth":976,"text":923},{"id":1505,"depth":966,"text":1508,"children":3224},[3225,3226,3227,3228],{"id":1511,"depth":976,"text":1514},{"id":1580,"depth":976,"text":1583},{"id":1986,"depth":976,"text":1989},{"id":2790,"depth":976,"text":2793},{"id":3007,"depth":966,"text":3010,"children":3230},[3231,3232],{"id":3013,"depth":976,"text":3016},{"id":3052,"depth":976,"text":3055},{"id":3082,"depth":966,"text":3085},{"id":3150,"depth":966,"text":3150},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":3236},"\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":3238},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm0 7h12v2H3zm0 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":3240},"\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":3242,"height":3242,"rotate":4,"vFlip":6,"hFlip":6,"body":3243},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>"]