[{"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\u002F02-strictmode-and-idempotent-effects":494,"i-ri:arrow-left-s-line":1206,"i-ri:menu-2-line":1208,"i-ri:arrow-right-s-line":1210},{"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":347,"path":347,"title":348,"updatedAt":21,"meta":498,"body":500,"toc":1189},"bm90ZTpub3Rlcy9yZWFjdC8wOS1yZWFjdC0xOC1pbi1wcmFjdGljZS8wMi1zdHJpY3Rtb2RlLWFuZC1pZGVtcG90ZW50LWVmZmVjdHMubWQ","note","notes\u002Freact\u002F09-react-18-in-practice\u002F02-strictmode-and-idempotent-effects.md",{"id":495,"type":496,"sourcePath":497,"slug":499,"title":348,"updatedAt":21,"lastUpdated":21},"react\u002F09-react-18-in-practice\u002F02-strictmode-and-idempotent-effects",{"type":501,"children":502},"root",[503,511,545,560,567,578,583,596,605,619,627,633,640,645,709,714,722,728,740,745,771,782,788,794,799,817,822,827,840,846,851,874,879,905,910,916,921,1000,1008,1014,1019,1032,1037,1043,1054,1062,1073,1081,1093,1101,1107,1112,1135,1140],{"type":504,"tag":505,"props":506,"children":508},"element","h1",{"id":507},"react-strictmode为什么会双调用源码机制视角",[509],{"type":510,"value":348},"text",{"type":504,"tag":512,"props":513,"children":514},"blockquote",{},[515],{"type":504,"tag":516,"props":517,"children":518},"p",{},[519,521,528,530,536,538,543],{"type":510,"value":520},"一句话结论：React 在开发环境的 ",{"type":504,"tag":522,"props":523,"children":525},"code",{"className":524},[],[526],{"type":510,"value":527},"StrictMode",{"type":510,"value":529}," 下会",{"type":504,"tag":531,"props":532,"children":533},"strong",{},[534],{"type":510,"value":535},"刻意制造“更苛刻的执行场景”",{"type":510,"value":537},"——包括对某些 render 相关函数的重复调用，以及在 React 18 中对 Effects 做“模拟卸载再挂载”的双执行——用来提前暴露「不纯渲染 \u002F 缺少清理 \u002F 依赖时序」等问题；这些行为",{"type":504,"tag":531,"props":539,"children":540},{},[541],{"type":510,"value":542},"不会发生在生产环境",{"type":510,"value":544},"。",{"type":504,"tag":512,"props":546,"children":547},{},[548],{"type":504,"tag":516,"props":549,"children":550},{},[551,553,558],{"type":510,"value":552},"注意：本文描述的“双调用”主要指 ",{"type":504,"tag":531,"props":554,"children":555},{},[556],{"type":510,"value":557},"React 18 开发环境 + StrictMode",{"type":510,"value":559}," 的行为。",{"type":504,"tag":561,"props":562,"children":564},"h2",{"id":563},"_1-strictmode-到底严格在哪里",[565],{"type":510,"value":566},"1. StrictMode 到底“严格”在哪里？",{"type":504,"tag":516,"props":568,"children":569},{},[570,572,577],{"type":510,"value":571},"StrictMode 不是一个运行时特性开关（不会改变生产行为），它更像一组 ",{"type":504,"tag":531,"props":573,"children":574},{},[575],{"type":510,"value":576},"DEV-only 的诊断器",{"type":510,"value":544},{"type":504,"tag":516,"props":579,"children":580},{},[581],{"type":510,"value":582},"从效果上看，它主要做两件事：",{"type":504,"tag":584,"props":585,"children":586},"ol",{},[587],{"type":504,"tag":588,"props":589,"children":590},"li",{},[591],{"type":504,"tag":531,"props":592,"children":593},{},[594],{"type":510,"value":595},"检测“不纯渲染”（impure render）",{"type":504,"tag":597,"props":598,"children":599},"ul",{},[600],{"type":504,"tag":588,"props":601,"children":602},{},[603],{"type":510,"value":604},"通过重复调用一些 render 相关逻辑，让“带副作用的渲染”更容易暴露（例如渲染时写全局变量、请求、订阅、随机数等）",{"type":504,"tag":584,"props":606,"children":608},{"start":607},2,[609],{"type":504,"tag":588,"props":610,"children":611},{},[612,617],{"type":504,"tag":531,"props":613,"children":614},{},[615],{"type":510,"value":616},"检测“副作用没有正确清理”（missing cleanup）",{"type":510,"value":618},"（React 18 新加强）",{"type":504,"tag":597,"props":620,"children":621},{},[622],{"type":504,"tag":588,"props":623,"children":624},{},[625],{"type":510,"value":626},"通过模拟「mount → unmount → mount」的生命周期，让缺少 cleanup 的 effect 更容易表现为：重复订阅、重复定时器、重复监听等",{"type":504,"tag":561,"props":628,"children":630},{"id":629},"_2-哪些东西会被重复执行现象对照",[631],{"type":510,"value":632},"2. 哪些东西会被“重复执行”？（现象对照）",{"type":504,"tag":634,"props":635,"children":637},"h3",{"id":636},"_21-render-相关为了抓不纯渲染",[638],{"type":510,"value":639},"2.1 Render 相关：为了抓“不纯渲染”",{"type":504,"tag":516,"props":641,"children":642},{},[643],{"type":510,"value":644},"在 DEV + StrictMode 下，React 会对一些函数做额外调用（典型包括）：",{"type":504,"tag":597,"props":646,"children":647},{},[648,658,675,692],{"type":504,"tag":588,"props":649,"children":650},{},[651,656],{"type":504,"tag":531,"props":652,"children":653},{},[654],{"type":510,"value":655},"函数组件的组件函数本身",{"type":510,"value":657},"（也就是 render 逻辑）",{"type":504,"tag":588,"props":659,"children":660},{},[661,667,669],{"type":504,"tag":522,"props":662,"children":664},{"className":663},[],[665],{"type":510,"value":666},"useState",{"type":510,"value":668}," 的 lazy initializer：",{"type":504,"tag":522,"props":670,"children":672},{"className":671},[],[673],{"type":510,"value":674},"useState(() => init())",{"type":504,"tag":588,"props":676,"children":677},{},[678,684,686],{"type":504,"tag":522,"props":679,"children":681},{"className":680},[],[682],{"type":510,"value":683},"useReducer",{"type":510,"value":685}," 的 initializer：",{"type":504,"tag":522,"props":687,"children":689},{"className":688},[],[690],{"type":510,"value":691},"useReducer(reducer, initArg, init)",{"type":504,"tag":588,"props":693,"children":694},{},[695,701,703],{"type":504,"tag":522,"props":696,"children":698},{"className":697},[],[699],{"type":510,"value":700},"useMemo",{"type":510,"value":702}," 的 factory：",{"type":504,"tag":522,"props":704,"children":706},{"className":705},[],[707],{"type":510,"value":708},"useMemo(() => compute(), deps)",{"type":504,"tag":516,"props":710,"children":711},{},[712],{"type":510,"value":713},"目的：如果这些函数不是“纯的”，重复调用会放大问题。",{"type":504,"tag":512,"props":715,"children":716},{},[717],{"type":504,"tag":516,"props":718,"children":719},{},[720],{"type":510,"value":721},"记法：凡是“在渲染阶段会运行的函数”，StrictMode 都倾向于让它们在 DEV 下更容易暴露副作用。",{"type":504,"tag":634,"props":723,"children":725},{"id":724},"_22-commit-相关effects为了抓缺少清理",[726],{"type":510,"value":727},"2.2 Commit 相关（Effects）：为了抓“缺少清理”",{"type":504,"tag":516,"props":729,"children":730},{},[731,733,738],{"type":510,"value":732},"React 18 DEV + StrictMode 下，会对 ",{"type":504,"tag":531,"props":734,"children":735},{},[736],{"type":510,"value":737},"Effects（尤其是 useEffect\u002FuseLayoutEffect）",{"type":510,"value":739}," 做“额外的 setup\u002Fcleanup 循环”。",{"type":504,"tag":516,"props":741,"children":742},{},[743],{"type":510,"value":744},"你观察到的现象通常是：",{"type":504,"tag":597,"props":746,"children":747},{},[748],{"type":504,"tag":588,"props":749,"children":750},{},[751,753],{"type":510,"value":752},"首次挂载时：\n",{"type":504,"tag":597,"props":754,"children":755},{},[756,761,766],{"type":504,"tag":588,"props":757,"children":758},{},[759],{"type":510,"value":760},"effect 执行一次",{"type":504,"tag":588,"props":762,"children":763},{},[764],{"type":510,"value":765},"然后立刻 cleanup 一次",{"type":504,"tag":588,"props":767,"children":768},{},[769],{"type":510,"value":770},"然后 effect 再执行一次",{"type":504,"tag":516,"props":772,"children":773},{},[774,776,781],{"type":510,"value":775},"这不是 bug，是 React 在 DEV 下",{"type":504,"tag":531,"props":777,"children":778},{},[779],{"type":510,"value":780},"模拟了一次卸载与重新挂载",{"type":510,"value":544},{"type":504,"tag":561,"props":783,"children":785},{"id":784},"_3-机制react-18-为什么要模拟卸载再挂载",[786],{"type":510,"value":787},"3. 机制：React 18 为什么要“模拟卸载再挂载”？",{"type":504,"tag":634,"props":789,"children":791},{"id":790},"_31-背景动机与并发渲染的关系",[792],{"type":510,"value":793},"3.1 背景动机（与并发渲染的关系）",{"type":504,"tag":516,"props":795,"children":796},{},[797],{"type":510,"value":798},"React 18 的并发能力让 UI 更新可能出现：",{"type":504,"tag":597,"props":800,"children":801},{},[802,807],{"type":504,"tag":588,"props":803,"children":804},{},[805],{"type":510,"value":806},"render 阶段可被中断\u002F重做\u002F丢弃",{"type":504,"tag":588,"props":808,"children":809},{},[810,812],{"type":510,"value":811},"effect 的安装与清理更需要",{"type":504,"tag":531,"props":813,"children":814},{},[815],{"type":510,"value":816},"可重入（idempotent）",{"type":504,"tag":516,"props":818,"children":819},{},[820],{"type":510,"value":821},"历史上很多代码默认“组件只 mount 一次”，effect 不写 cleanup 或 cleanup 不完整，在并发\u002F重试场景下就更危险。",{"type":504,"tag":516,"props":823,"children":824},{},[825],{"type":510,"value":826},"StrictMode 在 DEV 下把这种“危险代码”提前暴露出来：",{"type":504,"tag":597,"props":828,"children":829},{},[830,835],{"type":504,"tag":588,"props":831,"children":832},{},[833],{"type":510,"value":834},"如果 effect 没有 cleanup：你会看到重复订阅、重复事件监听",{"type":504,"tag":588,"props":836,"children":837},{},[838],{"type":510,"value":839},"如果 cleanup 写错：你会看到卸载后仍残留副作用",{"type":504,"tag":634,"props":841,"children":843},{"id":842},"_32-fiberflags-视角发生在-commit-阶段的额外流程",[844],{"type":510,"value":845},"3.2 Fiber\u002FFlags 视角（发生在 commit 阶段的额外流程）",{"type":504,"tag":516,"props":847,"children":848},{},[849],{"type":510,"value":850},"从架构上看：",{"type":504,"tag":597,"props":852,"children":853},{},[854,864],{"type":504,"tag":588,"props":855,"children":856},{},[857,862],{"type":504,"tag":531,"props":858,"children":859},{},[860],{"type":510,"value":861},"render 阶段",{"type":510,"value":863},"：生成 Fiber 树、计算变更",{"type":504,"tag":588,"props":865,"children":866},{},[867,872],{"type":504,"tag":531,"props":868,"children":869},{},[870],{"type":510,"value":871},"commit 阶段",{"type":510,"value":873},"：把变更落到宿主环境（DOM），并在特定时机执行 layout\u002Fpassive effects",{"type":504,"tag":516,"props":875,"children":876},{},[877],{"type":510,"value":878},"StrictMode 的“effect 双执行”本质发生在 commit 附近，React 在 DEV 下会走一个额外的流程，概念上类似：",{"type":504,"tag":584,"props":880,"children":881},{},[882,887],{"type":504,"tag":588,"props":883,"children":884},{},[885],{"type":510,"value":886},"正常 commit：挂载 DOM、执行 layout effects、安排 passive effects",{"type":504,"tag":588,"props":888,"children":889},{},[890,892],{"type":510,"value":891},"DEV 严格检查：\n",{"type":504,"tag":597,"props":893,"children":894},{},[895,900],{"type":504,"tag":588,"props":896,"children":897},{},[898],{"type":510,"value":899},"先执行一次“卸载路径”（cleanup layout\u002Fpassive effects）",{"type":504,"tag":588,"props":901,"children":902},{},[903],{"type":510,"value":904},"再执行一次“挂载路径”（重新 setup layout\u002Fpassive effects）",{"type":504,"tag":516,"props":906,"children":907},{},[908],{"type":510,"value":909},"你可以把它理解为 React 在 DEV 下做了一个“快速的 mount\u002Funmount\u002Fmount 回放”。",{"type":504,"tag":634,"props":911,"children":913},{"id":912},"_33-更贴近源码的关键词帮助你读源码时定位",[914],{"type":510,"value":915},"3.3 更贴近源码的关键词（帮助你读源码时定位）",{"type":504,"tag":516,"props":917,"children":918},{},[919],{"type":510,"value":920},"不同版本代码命名会有差异，但在 React 18 源码里你会经常看到类似概念：",{"type":504,"tag":597,"props":922,"children":923},{},[924,934,947,979],{"type":504,"tag":588,"props":925,"children":926},{},[927,932],{"type":504,"tag":522,"props":928,"children":930},{"className":929},[],[931],{"type":510,"value":220},{"type":510,"value":933},"：提交入口",{"type":504,"tag":588,"props":935,"children":936},{},[937,939,945],{"type":510,"value":938},"DEV-only 的 double invoke：类似 ",{"type":504,"tag":522,"props":940,"children":942},{"className":941},[],[943],{"type":510,"value":944},"commitDoubleInvokeEffectsInDEV",{"type":510,"value":946}," 的逻辑",{"type":504,"tag":588,"props":948,"children":949},{},[950,952],{"type":510,"value":951},"Layout\u002FPassive 两类 effect 的 mount\u002Funmount 函数族：\n",{"type":504,"tag":597,"props":953,"children":954},{},[955,968],{"type":504,"tag":588,"props":956,"children":957},{},[958,960,966],{"type":510,"value":959},"layout: ",{"type":504,"tag":522,"props":961,"children":963},{"className":962},[],[964],{"type":510,"value":965},"commitHookEffectListMount\u002FUnmount",{"type":510,"value":967},"（或同类命名）",{"type":504,"tag":588,"props":969,"children":970},{},[971,973],{"type":510,"value":972},"passive: ",{"type":504,"tag":522,"props":974,"children":976},{"className":975},[],[977],{"type":510,"value":978},"commitPassiveMountEffects\u002FcommitPassiveUnmountEffects",{"type":504,"tag":588,"props":980,"children":981},{},[982,984,990,992,998],{"type":510,"value":983},"与 StrictMode 相关的 DEV flags：常见如 ",{"type":504,"tag":522,"props":985,"children":987},{"className":986},[],[988],{"type":510,"value":989},"MountLayoutDev",{"type":510,"value":991},", ",{"type":504,"tag":522,"props":993,"children":995},{"className":994},[],[996],{"type":510,"value":997},"MountPassiveDev",{"type":510,"value":999},"（名字可能随版本演进）",{"type":504,"tag":512,"props":1001,"children":1002},{},[1003],{"type":504,"tag":516,"props":1004,"children":1005},{},[1006],{"type":510,"value":1007},"阅读建议：你如果已经看过本仓库的 Fiber\u002FcommitRoot 文章，可以把 StrictMode 的 DEV 行为当作“commitRoot 的一个 DEV 分支”。",{"type":504,"tag":561,"props":1009,"children":1011},{"id":1010},"_4-它为什么只在开发环境出现",[1012],{"type":510,"value":1013},"4. 它为什么只在开发环境出现？",{"type":504,"tag":516,"props":1015,"children":1016},{},[1017],{"type":510,"value":1018},"因为这些检查会：",{"type":504,"tag":597,"props":1020,"children":1021},{},[1022,1027],{"type":504,"tag":588,"props":1023,"children":1024},{},[1025],{"type":510,"value":1026},"增加额外的 mount\u002Funmount 开销",{"type":504,"tag":588,"props":1028,"children":1029},{},[1030],{"type":510,"value":1031},"改变某些时序（比如 effect 的执行次数）",{"type":504,"tag":516,"props":1033,"children":1034},{},[1035],{"type":510,"value":1036},"这类行为如果带到生产环境，既影响性能，也会改变业务逻辑。因此 React 把它限定为 DEV 工具。",{"type":504,"tag":561,"props":1038,"children":1040},{"id":1039},"_5-常见误区从机制推导出的结论",[1041],{"type":510,"value":1042},"5. 常见误区（从机制推导出的结论）",{"type":504,"tag":584,"props":1044,"children":1045},{},[1046],{"type":504,"tag":588,"props":1047,"children":1048},{},[1049],{"type":504,"tag":531,"props":1050,"children":1051},{},[1052],{"type":510,"value":1053},"“useEffect 怎么执行了两次？React 有 bug？”",{"type":504,"tag":597,"props":1055,"children":1056},{},[1057],{"type":504,"tag":588,"props":1058,"children":1059},{},[1060],{"type":510,"value":1061},"不是 bug，是 DEV + StrictMode 的诊断行为",{"type":504,"tag":584,"props":1063,"children":1064},{"start":607},[1065],{"type":504,"tag":588,"props":1066,"children":1067},{},[1068],{"type":504,"tag":531,"props":1069,"children":1070},{},[1071],{"type":510,"value":1072},"“我用 StrictMode 会不会让线上也执行两次？”",{"type":504,"tag":597,"props":1074,"children":1075},{},[1076],{"type":504,"tag":588,"props":1077,"children":1078},{},[1079],{"type":510,"value":1080},"不会。生产构建不会做这些 DEV double invoke",{"type":504,"tag":584,"props":1082,"children":1084},{"start":1083},3,[1085],{"type":504,"tag":588,"props":1086,"children":1087},{},[1088],{"type":504,"tag":531,"props":1089,"children":1090},{},[1091],{"type":510,"value":1092},"“我只要关掉 StrictMode 就好了？”",{"type":504,"tag":597,"props":1094,"children":1095},{},[1096],{"type":504,"tag":588,"props":1097,"children":1098},{},[1099],{"type":510,"value":1100},"关掉只是“把烟雾报警器拆了”，问题本身（缺少清理\u002F不纯渲染）仍然存在",{"type":504,"tag":561,"props":1102,"children":1104},{"id":1103},"_6-从架构角度的落地约束最少但关键",[1105],{"type":510,"value":1106},"6. 从架构角度的落地约束（最少但关键）",{"type":504,"tag":516,"props":1108,"children":1109},{},[1110],{"type":510,"value":1111},"既然 StrictMode 的目标是逼你写出“可重入”的逻辑，那么最关键的工程约束只有两条：",{"type":504,"tag":597,"props":1113,"children":1114},{},[1115,1125],{"type":504,"tag":588,"props":1116,"children":1117},{},[1118,1123],{"type":504,"tag":531,"props":1119,"children":1120},{},[1121],{"type":510,"value":1122},"渲染必须是纯的",{"type":510,"value":1124},"：组件函数里只做计算，不做订阅\u002F请求\u002F写外部状态",{"type":504,"tag":588,"props":1126,"children":1127},{},[1128,1133],{"type":504,"tag":531,"props":1129,"children":1130},{},[1131],{"type":510,"value":1132},"effects 必须可逆",{"type":510,"value":1134},"：setup 与 cleanup 必须配对且完整（订阅\u002F监听\u002F定时器\u002F外部实例）",{"type":504,"tag":561,"props":1136,"children":1138},{"id":1137},"关联阅读",[1139],{"type":510,"value":1137},{"type":504,"tag":597,"props":1141,"children":1142},{},[1143,1159,1174],{"type":504,"tag":588,"props":1144,"children":1145},{},[1146,1148],{"type":510,"value":1147},"并发模式概念：",{"type":504,"tag":1149,"props":1150,"children":1152},"a",{"href":1151},"..\u002F03-concurrent-mode\u002F01-concept.md",[1153],{"type":504,"tag":522,"props":1154,"children":1156},{"className":1155},[],[1157],{"type":510,"value":1158},"notes\u002F03-concurrent-mode\u002F01-concept.md",{"type":504,"tag":588,"props":1160,"children":1161},{},[1162,1164],{"type":510,"value":1163},"commitRoot（你已有）：",{"type":504,"tag":1149,"props":1165,"children":1167},{"href":1166},"..\u002F05-hooks\u002F14-commitRoot.md",[1168],{"type":504,"tag":522,"props":1169,"children":1171},{"className":1170},[],[1172],{"type":510,"value":1173},"notes\u002F05-hooks\u002F14-commitRoot.md",{"type":504,"tag":588,"props":1175,"children":1176},{},[1177,1179],{"type":510,"value":1178},"useEffect 实现原理（你已有）：",{"type":504,"tag":1149,"props":1180,"children":1182},{"href":1181},"..\u002F08-interview\u002F17-useEffect-impl.md",[1183],{"type":504,"tag":522,"props":1184,"children":1186},{"className":1185},[],[1187],{"type":510,"value":1188},"notes\u002F08-interview\u002F17-useEffect-impl.md",{"title":1190,"searchDepth":607,"depth":607,"links":1191},"",[1192,1193,1197,1202,1203,1204,1205],{"id":563,"depth":607,"text":566},{"id":629,"depth":607,"text":632,"children":1194},[1195,1196],{"id":636,"depth":1083,"text":639},{"id":724,"depth":1083,"text":727},{"id":784,"depth":607,"text":787,"children":1198},[1199,1200,1201],{"id":790,"depth":1083,"text":793},{"id":842,"depth":1083,"text":845},{"id":912,"depth":1083,"text":915},{"id":1010,"depth":607,"text":1013},{"id":1039,"depth":607,"text":1042},{"id":1103,"depth":607,"text":1106},{"id":1137,"depth":607,"text":1137},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1207},"\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":1209},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm0 7h12v2H3zm0 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1211},"\u003Cpath fill=\"currentColor\" d=\"m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z\"\u002F>"]