[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fecology":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fecology":806,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fecology":826},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":14,"pinned":15,"draft":15,"body":16,"seo":802,"stem":803,"id":804,"extension":805},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fecology","生态","React 本身专注 UI 层；路由、状态、数据请求、样式等由社区库补充。涵盖常用库、UI 组件库、开发工具、与 Vue 生态对照、选型建议与常见坑。","技能小册",[12,13],"react","ecology","2023-02-04",false,{"type":17,"value":18,"toc":789},"minimark",[19,22,37,41,49,53,238,242,326,342,346,349,416,425,428,464,468,539,542,570,573,634,637,690,693,711,714,717,785],[20,21,8],"h1",{"id":8},[23,24,25,26,31,32,36],"p",{},"React 本身专注 UI 层；路由、状态、数据请求、样式等由社区库补充。见 ",[27,28,30],"a",{"href":29},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fstate","状态管理","、",[27,33,35],{"href":34},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fproject","工程化","。",[38,39,40],"h2",{"id":40},"核心概念",[23,42,43,44,48],{},"React 的哲学是**「小核心 + 自由生态」",[45,46,47],"strong",{},"：官方只提供组件模型、Hooks、并发渲染这套核心机制，路由、全局状态、表单、数据请求全部交给社区。好处是团队可以按需组合最合适的工具，代价是新项目需要做","大量选型决策**，不同项目之间技术栈差异可能很大。",[38,50,52],{"id":51},"常用库2024-主流","常用库（2024+ 主流）",[54,55,56,72],"table",{},[57,58,59],"thead",{},[60,61,62,66,69],"tr",{},[63,64,65],"th",{},"领域",[63,67,68],{},"库",[63,70,71],{},"说明",[73,74,75,92,107,127,142,158,174,189,208,223],"tbody",{},[60,76,77,81,89],{},[78,79,80],"td",{},"路由",[78,82,83],{},[27,84,88],{"href":85,"rel":86},"https:\u002F\u002Freactrouter.com\u002F",[87],"nofollow","React Router",[78,90,91],{},"SPA 客户端路由",[60,93,94,97,104],{},[78,95,96],{},"服务端状态",[78,98,99],{},[27,100,103],{"href":101,"rel":102},"https:\u002F\u002Ftanstack.com\u002Fquery",[87],"TanStack Query",[78,105,106],{},"请求缓存、重试、失效",[60,108,109,112,124],{},[78,110,111],{},"客户端全局状态",[78,113,114,31,119],{},[27,115,118],{"href":116,"rel":117},"https:\u002F\u002Fredux-toolkit.js.org\u002F",[87],"Redux Toolkit",[27,120,123],{"href":121,"rel":122},"https:\u002F\u002Fzustand.docs.pmnd.rs\u002F",[87],"Zustand",[78,125,126],{},"见 state 章节",[60,128,129,132,139],{},[78,130,131],{},"表单",[78,133,134],{},[27,135,138],{"href":136,"rel":137},"https:\u002F\u002Freact-hook-form.com\u002F",[87],"React Hook Form",[78,140,141],{},"非受控为主、性能好",[60,143,144,147,155],{},[78,145,146],{},"样式",[78,148,149,150],{},"CSS Modules、Tailwind、",[27,151,154],{"href":152,"rel":153},"https:\u002F\u002Fzh-hans.react.dev\u002Flearn#adding-styles-to-your-app",[87],"CSS-in-JS 各库",[78,156,157],{},"按团队规范选型",[60,159,160,163,171],{},[78,161,162],{},"动画",[78,164,165,170],{},[27,166,169],{"href":167,"rel":168},"https:\u002F\u002Fmotion.dev\u002F",[87],"Motion","（原 Framer Motion）",[78,172,173],{},"声明式动画",[60,175,176,179,186],{},[78,177,178],{},"表格\u002F虚拟列表",[78,180,181],{},[27,182,185],{"href":183,"rel":184},"https:\u002F\u002Ftanstack.com\u002F",[87],"TanStack Table \u002F Virtual",[78,187,188],{},"无头 UI + 虚拟化",[60,190,191,194,205],{},[78,192,193],{},"元框架",[78,195,196,31,201],{},[27,197,200],{"href":198,"rel":199},"https:\u002F\u002Fnextjs.org\u002F",[87],"Next.js",[27,202,204],{"href":85,"rel":203},[87],"React Router v7（Framework Mode）",[78,206,207],{},"SSR、路由、数据加载；Remix 已并入 React Router v7，不再是独立框架",[60,209,210,213,220],{},[78,211,212],{},"表单校验",[78,214,215],{},[27,216,219],{"href":217,"rel":218},"https:\u002F\u002Fzod.dev\u002F",[87],"Zod",[78,221,222],{},"常与 React Hook Form 搭配做 schema 校验",[60,224,225,228,235],{},[78,226,227],{},"国际化",[78,229,230],{},[27,231,234],{"href":232,"rel":233},"https:\u002F\u002Freact.i18next.com\u002F",[87],"react-i18next",[78,236,237],{},"社区事实标准",[38,239,241],{"id":240},"示例tanstack-query-处理服务端状态","示例：TanStack Query 处理服务端状态",[243,244,249],"pre",{"className":245,"code":246,"language":247,"meta":248,"style":248},"language-tsx shiki shiki-themes material-theme-lighter github-light github-dark","import { useQuery } from \"@tanstack\u002Freact-query\";\n\nfunction UserProfile({ userId }: { userId: string }) {\n  const { data, isPending, error } = useQuery({\n    queryKey: [\"user\", userId],\n    queryFn: () => fetch(`\u002Fapi\u002Fusers\u002F${userId}`).then((r) => r.json()),\n  });\n\n  if (isPending) return \u003Cp>加载中…\u003C\u002Fp>;\n  if (error) return \u003Cp>加载失败\u003C\u002Fp>;\n  return \u003Cp>{data.name}\u003C\u002Fp>;\n}\n","tsx","",[250,251,252,260,267,273,279,285,291,297,302,308,314,320],"code",{"__ignoreMap":248},[253,254,257],"span",{"class":255,"line":256},"line",1,[253,258,259],{},"import { useQuery } from \"@tanstack\u002Freact-query\";\n",[253,261,263],{"class":255,"line":262},2,[253,264,266],{"emptyLinePlaceholder":265},true,"\n",[253,268,270],{"class":255,"line":269},3,[253,271,272],{},"function UserProfile({ userId }: { userId: string }) {\n",[253,274,276],{"class":255,"line":275},4,[253,277,278],{},"  const { data, isPending, error } = useQuery({\n",[253,280,282],{"class":255,"line":281},5,[253,283,284],{},"    queryKey: [\"user\", userId],\n",[253,286,288],{"class":255,"line":287},6,[253,289,290],{},"    queryFn: () => fetch(`\u002Fapi\u002Fusers\u002F${userId}`).then((r) => r.json()),\n",[253,292,294],{"class":255,"line":293},7,[253,295,296],{},"  });\n",[253,298,300],{"class":255,"line":299},8,[253,301,266],{"emptyLinePlaceholder":265},[253,303,305],{"class":255,"line":304},9,[253,306,307],{},"  if (isPending) return \u003Cp>加载中…\u003C\u002Fp>;\n",[253,309,311],{"class":255,"line":310},10,[253,312,313],{},"  if (error) return \u003Cp>加载失败\u003C\u002Fp>;\n",[253,315,317],{"class":255,"line":316},11,[253,318,319],{},"  return \u003Cp>{data.name}\u003C\u002Fp>;\n",[253,321,323],{"class":255,"line":322},12,[253,324,325],{},"}\n",[23,327,328,329,332,333,336,337,341],{},"TanStack Query 自动处理",[45,330,331],{},"缓存、重试、后台重新验证、竞态请求取消","等，比手写 ",[250,334,335],{},"useEffect + useState"," 更省心，也避免了",[27,338,340],{"href":339},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Feffect","Effect"," 一节中提到的「服务端数据缓存不适合手写 Effect」问题。",[38,343,345],{"id":344},"ui-组件库","UI 组件库",[23,347,348],{},"Ant Design、MUI、Radix + shadcn\u002Fui 等；选型看设计语言、可访问性、包体积与 Tree Shaking 支持。",[54,350,351,360],{},[57,352,353],{},[60,354,355,357],{},[63,356,68],{},[63,358,359],{},"特点",[73,361,362,374,386,404],{},[60,363,364,371],{},[78,365,366],{},[27,367,370],{"href":368,"rel":369},"https:\u002F\u002Fant.design\u002F",[87],"Ant Design",[78,372,373],{},"企业中后台常用，组件齐全、设计语言统一",[60,375,376,383],{},[78,377,378],{},[27,379,382],{"href":380,"rel":381},"https:\u002F\u002Fmui.com\u002F",[87],"MUI",[78,384,385],{},"Material Design 风格，生态成熟",[60,387,388,401],{},[78,389,390,395,396],{},[27,391,394],{"href":392,"rel":393},"https:\u002F\u002Fwww.radix-ui.com\u002F",[87],"Radix UI"," + ",[27,397,400],{"href":398,"rel":399},"https:\u002F\u002Fui.shadcn.com\u002F",[87],"shadcn\u002Fui",[78,402,403],{},"无样式行为组件 + 可复制粘贴的样式方案，定制自由度高",[60,405,406,413],{},[78,407,408],{},[27,409,412],{"href":410,"rel":411},"https:\u002F\u002Fchakra-ui.com\u002F",[87],"Chakra UI",[78,414,415],{},"主题化友好，API 简洁",[23,417,418,420,421,424],{},[250,419,400],{}," 与传统组件库不同：它不是 npm 依赖，而是把组件源码",[45,422,423],{},"生成到你的项目里","，方便深度定制但也意味着升级需要手动同步。",[38,426,427],{"id":427},"开发工具",[429,430,431,442,448,458],"ul",{},[432,433,434,437,438,441],"li",{},[45,435,436],{},"ESLint"," ",[250,439,440],{},"eslint-plugin-react-hooks","：强制 Hooks 规则（依赖数组完整性、条件调用检测等）。",[432,443,444,447],{},[45,445,446],{},"React DevTools","：组件树与 Profiler。",[432,449,450,453,454,36],{},[45,451,452],{},"TypeScript","：见 ",[27,455,457],{"href":456},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftypescript","typescript",[432,459,460,463],{},[45,461,462],{},"Storybook","：组件独立开发与可视化文档。",[38,465,467],{"id":466},"与-vue-生态对照简表","与 Vue 生态对照（简表）",[54,469,470,483],{},[57,471,472],{},[60,473,474,477,480],{},[63,475,476],{},"能力",[63,478,479],{},"React",[63,481,482],{},"Vue",[73,484,485,496,507,518,529],{},[60,486,487,490,493],{},[78,488,489],{},"官方元框架",[78,491,492],{},"无（社区 Next 等）",[78,494,495],{},"Nuxt",[60,497,498,501,504],{},[78,499,500],{},"官方路由",[78,502,503],{},"无（React Router）",[78,505,506],{},"Vue Router",[60,508,509,512,515],{},[78,510,511],{},"官方状态",[78,513,514],{},"无（Redux 等）",[78,516,517],{},"Pinia",[60,519,520,523,526],{},[78,521,522],{},"组件库风格",[78,524,525],{},"多为「行为 + 样式分离」（Radix）",[78,527,528],{},"多为「开箱即用」（Element Plus）",[60,530,531,533,536],{},[78,532,212],{},[78,534,535],{},"Zod + RHF 组合",[78,537,538],{},"VeeValidate + Yup\u002FZod",[38,540,541],{"id":541},"选型建议",[429,543,544,550,556,563],{},[432,545,546,547,36],{},"新的中后台项目：",[250,548,549],{},"Vite + React Router + TanStack Query + Zustand（若需要全局状态）+ Ant Design\u002Fshadcn",[432,551,552,553,555],{},"需要 SEO、混合渲染、服务端组件：直接上 ",[250,554,200],{},"（App Router），减少自己拼装路由和数据获取层的成本。",[432,557,558,559,562],{},"表单密集型系统：",[250,560,561],{},"React Hook Form + Zod","，配合 UI 库的受控组件适配层。",[432,564,565,566,569],{},"团队对包体积、定制自由度要求高：",[250,567,568],{},"Radix + shadcn\u002Fui"," 优于「一次性引入整套设计语言」的组件库。",[38,571,572],{"id":572},"常见坑",[54,574,575,588],{},[57,576,577],{},[60,578,579,582,585],{},[63,580,581],{},"现象",[63,583,584],{},"常见原因",[63,586,587],{},"处理",[73,589,590,601,612,623],{},[60,591,592,595,598],{},[78,593,594],{},"选了多个状态库混用，代码风格割裂",[78,596,597],{},"团队没有统一约定「什么状态放哪」",[78,599,600],{},"明确服务端状态用 TanStack Query，客户端全局状态用一种库",[60,602,603,606,609],{},[78,604,605],{},"Ant Design 按需引入后仍很大",[78,607,608],{},"全局样式或未做正确的 tree-shaking 配置",[78,610,611],{},"确认按组件导入方式与打包工具配置",[60,613,614,617,620],{},[78,615,616],{},"shadcn\u002Fui 组件升级困难",[78,618,619],{},"组件代码已被复制进项目并可能被修改",[78,621,622],{},"升级前对比官方最新版本手动合并变更",[60,624,625,628,631],{},[78,626,627],{},"Hooks 规则报错但看起来没问题",[78,629,630],{},"条件语句里调用了 Hook，或依赖数组遗漏",[78,632,633],{},"严格遵循 Hooks 规则，交给 ESLint 插件把关",[38,635,636],{"id":636},"生态选型速查",[54,638,639,649],{},[57,640,641],{},[60,642,643,646],{},[63,644,645],{},"需求",[63,647,648],{},"建议",[73,650,651,659,667,675,682],{},[60,652,653,656],{},[78,654,655],{},"快速搭建中后台",[78,657,658],{},"Vite + Ant Design + React Router",[60,660,661,664],{},[78,662,663],{},"SEO\u002F内容站",[78,665,666],{},"Next.js（App Router）或 Astro",[60,668,669,672],{},[78,670,671],{},"高度定制视觉",[78,673,674],{},"Radix UI + shadcn\u002Fui + Tailwind",[60,676,677,680],{},[78,678,679],{},"复杂表单校验",[78,681,561],{},[60,683,684,687],{},[78,685,686],{},"服务端数据密集型应用",[78,688,689],{},"TanStack Query（缓存\u002F重试\u002F失效）",[38,691,692],{"id":692},"延伸阅读",[429,694,695,700,705],{},[432,696,697,699],{},[27,698,30],{"href":29},"：客户端\u002F服务端状态选型细节",[432,701,702,704],{},[27,703,35],{"href":34},"：Vite\u002FNext.js 项目搭建",[432,706,707,710],{},[27,708,709],{"href":339},"Effect 与副作用","：为何服务端数据优先用 TanStack Query",[38,712,713],{"id":713},"参考文献",[23,715,716],{},"以下链接在编写时均可正常访问：",[54,718,719,728],{},[57,720,721],{},[60,722,723,726],{},[63,724,725],{},"资料",[63,727,71],{},[73,729,730,742,754,766,775],{},[60,731,732,739],{},[78,733,734],{},[27,735,738],{"href":736,"rel":737},"https:\u002F\u002Fzh-hans.react.dev\u002Flearn",[87],"React 官方：学习资源",[78,740,741],{},"中文",[60,743,744,751],{},[78,745,746],{},[27,747,750],{"href":748,"rel":749},"https:\u002F\u002Fgithub.com\u002Fenaqx\u002Fawesome-react",[87],"Awesome React",[78,752,753],{},"社区清单（英文）",[60,755,756,763],{},[78,757,758],{},[27,759,762],{"href":760,"rel":761},"https:\u002F\u002Fnpmtrends.com\u002F",[87],"npm trends",[78,764,765],{},"下载量对比（选型参考）",[60,767,768,773],{},[78,769,770],{},[27,771,103],{"href":101,"rel":772},[87],[78,774,96],{},[60,776,777,782],{},[78,778,779],{},[27,780,400],{"href":398,"rel":781},[87],[78,783,784],{},"组件方案",[786,787,788],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":248,"searchDepth":262,"depth":262,"links":790},[791,792,793,794,795,796,797,798,799,800,801],{"id":40,"depth":262,"text":40},{"id":51,"depth":262,"text":52},{"id":240,"depth":262,"text":241},{"id":344,"depth":262,"text":345},{"id":427,"depth":262,"text":427},{"id":466,"depth":262,"text":467},{"id":541,"depth":262,"text":541},{"id":572,"depth":262,"text":572},{"id":636,"depth":262,"text":636},{"id":692,"depth":262,"text":692},{"id":713,"depth":262,"text":713},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fframe\u002FReact\u002Fecology","knowledge\u002Fknowledge\u002Fbooklet\u002Fframe\u002FReact\u002Fecology.md","md",{"items":807},[808,812,814,816,820,824],{"path":809,"title":810,"description":811,"category":10,"score":287},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Frendering","渲染与协调","React 将组件渲染为虚拟 DOM 树，再协调（reconciliation）到浏览器 DOM。理解该过程有助于解释 key、memo 与性能优化。涵盖渲染流程、Fiber、startTransition、Suspense、最佳实践与常见坑。",{"path":34,"title":35,"description":813,"category":10,"score":287},"新建 React 项目时，官方与社区主流工具为 Vite；全栈场景常用 Next.js。涵盖 Vite + React、Create React App 现状、Next.js、目录结构、环境变量、部署、最佳实践与常见坑。",{"path":456,"title":452,"description":815,"category":10,"score":287},"React 官方推荐 TypeScript。类型主要落在 Props、事件、Ref 与 Hooks 返回值上。见 组件。",{"path":817,"title":818,"description":819,"category":10,"score":287},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftest","测试","React 组件测试推荐 React Testing Library（RTL）：从用户可见行为断言，而非实现细节。运行器常用 Vitest 或 Jest。涵盖安装配置、查询优先级、异步测试、Mock 网络请求、最佳实践与常见坑。",{"path":821,"title":822,"description":823,"category":10,"score":287},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fperformance\u002Fbuild","构建与分包","通过代码分割与构建配置减小首屏 JavaScript 体积。涵盖 React.lazy\u002FSuspense、路由级分割、Tree Shaking、Vite 生产构建、体积分析、最佳实践与常见坑。运行时优化见 runtime。",{"path":339,"title":709,"description":825,"category":10,"score":287},"useEffect 用于在组件渲染后执行与外部系统同步的逻辑（请求、订阅、手动改 DOM 等）。涵盖基本用法、依赖数组、适用\u002F不适用场景、useLayoutEffect、最佳实践与常见坑。",{"series":827,"title":12,"items":828,"index":275,"prev":875,"next":876},"booklet\u002Fframe\u002Freact",[829,833,835,839,843,844,846,850,854,856,858,861,865,869,871,873],{"path":830,"title":831,"date":832,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fbasics","React 基础","2020-02-12",{"path":821,"title":822,"date":834,"pinned":15},"2025-07-23",{"path":836,"title":837,"date":838,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fcomponents","组件与 Props","2020-06-11",{"path":840,"title":841,"date":842,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fcontext","Context","2021-10-16",{"path":7,"title":8,"date":14,"pinned":15},{"path":339,"title":709,"date":845,"pinned":15},"2024-10-11",{"path":847,"title":848,"date":849,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fjsx","JSX 与语法","2020-02-29",{"path":851,"title":852,"date":853,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fmemo","Memo、Callback 与 Ref","2021-02-28",{"path":34,"title":35,"date":855,"pinned":15},"2026-05-08",{"path":809,"title":810,"date":857,"pinned":15},"2026-07-10",{"path":859,"title":80,"date":860,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Frouter","2023-09-06",{"path":862,"title":863,"date":864,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fperformance\u002Fruntime","运行时优化","2020-02-05",{"path":866,"title":867,"date":868,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fstate","State 与 Reducer","2021-02-21",{"path":29,"title":30,"date":870,"pinned":15},"2024-02-07",{"path":817,"title":818,"date":872,"pinned":15},"2025-09-26",{"path":456,"title":452,"date":874,"pinned":15},"2026-03-13",{"path":840,"title":841,"date":842,"pinned":15},{"path":339,"title":709,"date":845,"pinned":15}]