[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fjsx":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fjsx":424,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fjsx":448},{"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":420,"stem":421,"id":422,"extension":423},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fjsx","JSX 与语法","JSX 是 JavaScript 的语法扩展，在代码中编写类似 HTML 的结构。编译后变为 React.createElement 调用。见 React 基础。","技能小册",[12,13],"react","jsx","2020-02-29",false,{"type":17,"value":18,"toc":411},"minimark",[19,23,38,42,58,149,152,160,206,209,262,274,277,311,315,339,343,352,355,358,407],[20,21,8],"h1",{"id":22},"jsx-与语法",[24,25,26,27,31,32,37],"p",{},"JSX 是 JavaScript 的语法扩展，在代码中编写类似 HTML 的结构。编译后变为 ",[28,29,30],"code",{},"React.createElement"," 调用。见 ",[33,34,36],"a",{"href":35},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fbasics","React 基础","。",[39,40,41],"h2",{"id":41},"基本规则",[43,44,49],"pre",{"className":45,"code":46,"language":47,"meta":48,"style":48},"language-tsx shiki shiki-themes material-theme-lighter github-light github-dark","const element = \u003Ch1 className=\"title\">Hello\u003C\u002Fh1>;\n","tsx","",[28,50,51],{"__ignoreMap":48},[52,53,56],"span",{"class":54,"line":55},"line",1,[52,57,46],{},[59,60,61,74],"table",{},[62,63,64],"thead",{},[65,66,67,71],"tr",{},[68,69,70],"th",{},"规则",[68,72,73],{},"说明",[75,76,77,94,108,121,136],"tbody",{},[65,78,79,83],{},[80,81,82],"td",{},"必须有一个根节点",[80,84,85,86,89,90,93],{},"多个并列节点用 ",[28,87,88],{},"\u003C>...\u003C\u002F>","（Fragment）或 ",[28,91,92],{},"\u003CFragment>"," 包裹",[65,95,96,102],{},[80,97,98,99],{},"使用 ",[28,100,101],{},"className",[80,103,104,105],{},"对应 HTML 的 ",[28,106,107],{},"class",[65,109,110,115],{},[80,111,98,112],{},[28,113,114],{},"htmlFor",[80,116,117,118],{},"对应 ",[28,119,120],{},"for",[65,122,123,126],{},[80,124,125],{},"自闭合标签",[80,127,128,131,132,135],{},[28,129,130],{},"\u003Cimg \u002F>","、",[28,133,134],{},"\u003Cinput \u002F>"," 等须闭合",[65,137,138,141],{},[80,139,140],{},"驼峰属性",[80,142,143,131,146],{},[28,144,145],{},"onClick",[28,147,148],{},"tabIndex",[39,150,151],{"id":151},"嵌入表达式",[24,153,154,155,159],{},"花括号内可写任意 ",[156,157,158],"strong",{},"JavaScript 表达式","（非语句）：",[43,161,163],{"className":45,"code":162,"language":47,"meta":48,"style":48},"const name = \"React\";\nconst count = 3;\nreturn (\n  \u003Cp>\n    {name} · {count > 0 ? \"有数据\" : \"空\"}\n  \u003C\u002Fp>\n);\n",[28,164,165,170,176,182,188,194,200],{"__ignoreMap":48},[52,166,167],{"class":54,"line":55},[52,168,169],{},"const name = \"React\";\n",[52,171,173],{"class":54,"line":172},2,[52,174,175],{},"const count = 3;\n",[52,177,179],{"class":54,"line":178},3,[52,180,181],{},"return (\n",[52,183,185],{"class":54,"line":184},4,[52,186,187],{},"  \u003Cp>\n",[52,189,191],{"class":54,"line":190},5,[52,192,193],{},"    {name} · {count > 0 ? \"有数据\" : \"空\"}\n",[52,195,197],{"class":54,"line":196},6,[52,198,199],{},"  \u003C\u002Fp>\n",[52,201,203],{"class":54,"line":202},7,[52,204,205],{},");\n",[39,207,208],{"id":208},"条件与列表",[43,210,212],{"className":45,"code":211,"language":47,"meta":48,"style":48},"\u002F\u002F 条件\n{isLoggedIn ? \u003CDashboard \u002F> : \u003CLogin \u002F>}\n\n\u002F\u002F 列表（必须稳定 key）\n\u003Cul>\n  {items.map((item) => (\n    \u003Cli key={item.id}>{item.title}\u003C\u002Fli>\n  ))}\n\u003C\u002Ful>\n",[28,213,214,219,224,230,235,240,245,250,256],{"__ignoreMap":48},[52,215,216],{"class":54,"line":55},[52,217,218],{},"\u002F\u002F 条件\n",[52,220,221],{"class":54,"line":172},[52,222,223],{},"{isLoggedIn ? \u003CDashboard \u002F> : \u003CLogin \u002F>}\n",[52,225,226],{"class":54,"line":178},[52,227,229],{"emptyLinePlaceholder":228},true,"\n",[52,231,232],{"class":54,"line":184},[52,233,234],{},"\u002F\u002F 列表（必须稳定 key）\n",[52,236,237],{"class":54,"line":190},[52,238,239],{},"\u003Cul>\n",[52,241,242],{"class":54,"line":196},[52,243,244],{},"  {items.map((item) => (\n",[52,246,247],{"class":54,"line":202},[52,248,249],{},"    \u003Cli key={item.id}>{item.title}\u003C\u002Fli>\n",[52,251,253],{"class":54,"line":252},8,[52,254,255],{},"  ))}\n",[52,257,259],{"class":54,"line":258},9,[52,260,261],{},"\u003C\u002Ful>\n",[24,263,264,269,270,273],{},[156,265,266],{},[28,267,268],{},"key","：应使用列表项稳定唯一 id，",[156,271,272],{},"不要用随机数或数组下标","（在重排、插入时会导致状态错乱），除非列表静态且不重排。",[39,275,276],{"id":276},"样式",[43,278,280],{"className":45,"code":279,"language":47,"meta":48,"style":48},"\u002F\u002F 内联对象\n\u003Cdiv style={{ color: \"red\", marginTop: 8 }} \u002F>\n\n\u002F\u002F CSS 类\nimport styles from \".\u002FCard.module.css\";\n\u003Cdiv className={styles.card} \u002F>\n",[28,281,282,287,292,296,301,306],{"__ignoreMap":48},[52,283,284],{"class":54,"line":55},[52,285,286],{},"\u002F\u002F 内联对象\n",[52,288,289],{"class":54,"line":172},[52,290,291],{},"\u003Cdiv style={{ color: \"red\", marginTop: 8 }} \u002F>\n",[52,293,294],{"class":54,"line":178},[52,295,229],{"emptyLinePlaceholder":228},[52,297,298],{"class":54,"line":184},[52,299,300],{},"\u002F\u002F CSS 类\n",[52,302,303],{"class":54,"line":190},[52,304,305],{},"import styles from \".\u002FCard.module.css\";\n",[52,307,308],{"class":54,"line":196},[52,309,310],{},"\u003Cdiv className={styles.card} \u002F>\n",[39,312,314],{"id":313},"与-html-的差异常见","与 HTML 的差异（常见）",[316,317,318,325,336],"ul",{},[319,320,321,322,324],"li",{},"事件：",[28,323,145],{}," 接收函数，不是字符串；合成事件（SyntheticEvent）封装浏览器事件。",[319,326,327,330,331,335],{},[28,328,329],{},"dangerouslySetInnerHTML","：仅用于已消毒的 HTML 字符串，否则有 XSS 风险（见 ",[33,332,334],{"href":333},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fsafe","安全","）。",[319,337,338],{},"小写标签为内置 DOM 元素；大写开头为自定义组件。",[39,340,342],{"id":341},"typescript","TypeScript",[24,344,345,348,349,37],{},[28,346,347],{},".tsx"," 文件中可为 props 与事件标注类型；详见 ",[33,350,342],{"href":351},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftypescript",[39,353,354],{"id":354},"参考文献",[24,356,357],{},"以下链接在编写时均可正常访问：",[59,359,360,369],{},[62,361,362],{},[65,363,364,367],{},[68,365,366],{},"资料",[68,368,73],{},[75,370,371,384,396],{},[65,372,373,381],{},[80,374,375],{},[33,376,380],{"href":377,"rel":378},"https:\u002F\u002Fzh-hans.react.dev\u002Flearn\u002Fwriting-markup-with-jsx",[379],"nofollow","React：编写 JSX",[80,382,383],{},"标记语法",[65,385,386,393],{},[80,387,388],{},[33,389,392],{"href":390,"rel":391},"https:\u002F\u002Fzh-hans.react.dev\u002Flearn\u002Fconditional-rendering",[379],"React：条件渲染",[80,394,395],{},"条件",[65,397,398,405],{},[80,399,400],{},[33,401,404],{"href":402,"rel":403},"https:\u002F\u002Fzh-hans.react.dev\u002Flearn\u002Frendering-lists",[379],"React：列表渲染",[80,406,268],{},[408,409,410],"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":48,"searchDepth":172,"depth":172,"links":412},[413,414,415,416,417,418,419],{"id":41,"depth":172,"text":41},{"id":151,"depth":172,"text":151},{"id":208,"depth":172,"text":208},{"id":276,"depth":172,"text":276},{"id":313,"depth":172,"text":314},{"id":341,"depth":172,"text":342},{"id":354,"depth":172,"text":354},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fframe\u002FReact\u002Fjsx","knowledge\u002Fknowledge\u002Fbooklet\u002Fframe\u002FReact\u002Fjsx.md","md",{"items":425},[426,430,434,436,440,444],{"path":427,"title":428,"description":429,"category":10,"score":196},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Frendering","渲染与协调","React 将组件渲染为虚拟 DOM 树，再协调（reconciliation）到浏览器 DOM。理解该过程有助于解释 key、memo 与性能优化。涵盖渲染流程、Fiber、startTransition、Suspense、最佳实践与常见坑。",{"path":431,"title":432,"description":433,"category":10,"score":196},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fproject","工程化","新建 React 项目时，官方与社区主流工具为 Vite；全栈场景常用 Next.js。涵盖 Vite + React、Create React App 现状、Next.js、目录结构、环境变量、部署、最佳实践与常见坑。",{"path":351,"title":342,"description":435,"category":10,"score":196},"React 官方推荐 TypeScript。类型主要落在 Props、事件、Ref 与 Hooks 返回值上。见 组件。",{"path":437,"title":438,"description":439,"category":10,"score":196},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftest","测试","React 组件测试推荐 React Testing Library（RTL）：从用户可见行为断言，而非实现细节。运行器常用 Vitest 或 Jest。涵盖安装配置、查询优先级、异步测试、Mock 网络请求、最佳实践与常见坑。",{"path":441,"title":442,"description":443,"category":10,"score":196},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fperformance\u002Fbuild","构建与分包","通过代码分割与构建配置减小首屏 JavaScript 体积。涵盖 React.lazy\u002FSuspense、路由级分割、Tree Shaking、Vite 生产构建、体积分析、最佳实践与常见坑。运行时优化见 runtime。",{"path":445,"title":446,"description":447,"category":10,"score":196},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Feffect","Effect 与副作用","useEffect 用于在组件渲染后执行与外部系统同步的逻辑（请求、订阅、手动改 DOM 等）。涵盖基本用法、依赖数组、适用\u002F不适用场景、useLayoutEffect、最佳实践与常见坑。",{"series":449,"title":12,"items":450,"index":196,"prev":498,"next":499},"booklet\u002Fframe\u002Freact",[451,453,455,459,463,467,469,470,474,476,478,482,486,490,494,496],{"path":35,"title":36,"date":452,"pinned":15},"2020-02-12",{"path":441,"title":442,"date":454,"pinned":15},"2025-07-23",{"path":456,"title":457,"date":458,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fcomponents","组件与 Props","2020-06-11",{"path":460,"title":461,"date":462,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fcontext","Context","2021-10-16",{"path":464,"title":465,"date":466,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fecology","生态","2023-02-04",{"path":445,"title":446,"date":468,"pinned":15},"2024-10-11",{"path":7,"title":8,"date":14,"pinned":15},{"path":471,"title":472,"date":473,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fmemo","Memo、Callback 与 Ref","2021-02-28",{"path":431,"title":432,"date":475,"pinned":15},"2026-05-08",{"path":427,"title":428,"date":477,"pinned":15},"2026-07-10",{"path":479,"title":480,"date":481,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Frouter","路由","2023-09-06",{"path":483,"title":484,"date":485,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fperformance\u002Fruntime","运行时优化","2020-02-05",{"path":487,"title":488,"date":489,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fstate","State 与 Reducer","2021-02-21",{"path":491,"title":492,"date":493,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fstate","状态管理","2024-02-07",{"path":437,"title":438,"date":495,"pinned":15},"2025-09-26",{"path":351,"title":342,"date":497,"pinned":15},"2026-03-13",{"path":445,"title":446,"date":468,"pinned":15},{"path":471,"title":472,"date":473,"pinned":15}]