[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftypescript":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftypescript":394,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftypescript":420},{"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":390,"stem":391,"id":392,"extension":393},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftypescript","TypeScript","React 官方推荐 TypeScript。类型主要落在 Props、事件、Ref 与 Hooks 返回值上。见 组件。","技能小册",[12,13],"react","typescript","2026-03-13",false,{"type":17,"value":18,"toc":381},"minimark",[19,22,48,53,144,153,157,181,184,226,229,289,293,308,310,320,323,326,377],[20,21,8],"h1",{"id":13},[23,24,25,26,30,31,30,34,37,38,41,42,47],"p",{},"React 官方推荐 TypeScript。类型主要落在 ",[27,28,29],"strong",{},"Props","、",[27,32,33],{},"事件",[27,35,36],{},"Ref"," 与 ",[27,39,40],{},"Hooks"," 返回值上。见 ",[43,44,46],"a",{"href":45},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fcomponents","组件","。",[49,50,52],"h2",{"id":51},"函数组件-props","函数组件 Props",[54,55,60],"pre",{"className":56,"code":57,"language":58,"meta":59,"style":59},"language-tsx shiki shiki-themes material-theme-lighter github-light github-dark","type ButtonProps = {\n  label: string;\n  disabled?: boolean;\n  onClick: (event: React.MouseEvent\u003CHTMLButtonElement>) => void;\n};\n\nexport function Button({ label, disabled, onClick }: ButtonProps) {\n  return (\n    \u003Cbutton type=\"button\" disabled={disabled} onClick={onClick}>\n      {label}\n    \u003C\u002Fbutton>\n  );\n}\n","tsx","",[61,62,63,71,77,83,89,95,102,108,114,120,126,132,138],"code",{"__ignoreMap":59},[64,65,68],"span",{"class":66,"line":67},"line",1,[64,69,70],{},"type ButtonProps = {\n",[64,72,74],{"class":66,"line":73},2,[64,75,76],{},"  label: string;\n",[64,78,80],{"class":66,"line":79},3,[64,81,82],{},"  disabled?: boolean;\n",[64,84,86],{"class":66,"line":85},4,[64,87,88],{},"  onClick: (event: React.MouseEvent\u003CHTMLButtonElement>) => void;\n",[64,90,92],{"class":66,"line":91},5,[64,93,94],{},"};\n",[64,96,98],{"class":66,"line":97},6,[64,99,101],{"emptyLinePlaceholder":100},true,"\n",[64,103,105],{"class":66,"line":104},7,[64,106,107],{},"export function Button({ label, disabled, onClick }: ButtonProps) {\n",[64,109,111],{"class":66,"line":110},8,[64,112,113],{},"  return (\n",[64,115,117],{"class":66,"line":116},9,[64,118,119],{},"    \u003Cbutton type=\"button\" disabled={disabled} onClick={onClick}>\n",[64,121,123],{"class":66,"line":122},10,[64,124,125],{},"      {label}\n",[64,127,129],{"class":66,"line":128},11,[64,130,131],{},"    \u003C\u002Fbutton>\n",[64,133,135],{"class":66,"line":134},12,[64,136,137],{},"  );\n",[64,139,141],{"class":66,"line":140},13,[64,142,143],{},"}\n",[23,145,146,149,150,47],{},[61,147,148],{},"children"," 常用 ",[61,151,152],{},"React.ReactNode",[49,154,156],{"id":155},"带-children-的组件","带 children 的组件",[54,158,160],{"className":56,"code":159,"language":58,"meta":59,"style":59},"type CardProps = {\n  title: string;\n  children: React.ReactNode;\n};\n",[61,161,162,167,172,177],{"__ignoreMap":59},[64,163,164],{"class":66,"line":67},[64,165,166],{},"type CardProps = {\n",[64,168,169],{"class":66,"line":73},[64,170,171],{},"  title: string;\n",[64,173,174],{"class":66,"line":79},[64,175,176],{},"  children: React.ReactNode;\n",[64,178,179],{"class":66,"line":85},[64,180,94],{},[49,182,183],{"id":183},"泛型组件",[54,185,187],{"className":56,"code":186,"language":58,"meta":59,"style":59},"type ListProps\u003CT> = {\n  items: T[];\n  renderItem: (item: T) => React.ReactNode;\n};\n\nfunction List\u003CT>({ items, renderItem }: ListProps\u003CT>) {\n  return \u003Cul>{items.map((item) => \u003Cli key={String(item)}>{renderItem(item)}\u003C\u002Fli>)}\u003C\u002Ful>;\n}\n",[61,188,189,194,199,204,208,212,217,222],{"__ignoreMap":59},[64,190,191],{"class":66,"line":67},[64,192,193],{},"type ListProps\u003CT> = {\n",[64,195,196],{"class":66,"line":73},[64,197,198],{},"  items: T[];\n",[64,200,201],{"class":66,"line":79},[64,202,203],{},"  renderItem: (item: T) => React.ReactNode;\n",[64,205,206],{"class":66,"line":85},[64,207,94],{},[64,209,210],{"class":66,"line":91},[64,211,101],{"emptyLinePlaceholder":100},[64,213,214],{"class":66,"line":97},[64,215,216],{},"function List\u003CT>({ items, renderItem }: ListProps\u003CT>) {\n",[64,218,219],{"class":66,"line":104},[64,220,221],{},"  return \u003Cul>{items.map((item) => \u003Cli key={String(item)}>{renderItem(item)}\u003C\u002Fli>)}\u003C\u002Ful>;\n",[64,223,224],{"class":66,"line":110},[64,225,143],{},[49,227,228],{"id":228},"常用类型",[230,231,232,245],"table",{},[233,234,235],"thead",{},[236,237,238,242],"tr",{},[239,240,241],"th",{},"类型",[239,243,244],{},"用途",[246,247,248,259,269,279],"tbody",{},[236,249,250,256],{},[251,252,253],"td",{},[61,254,255],{},"React.FC",[251,257,258],{},"可选；官方不强制，显式写 Props 更清晰",[236,260,261,266],{},[251,262,263],{},[61,264,265],{},"React.ComponentProps\u003C\"input\">",[251,267,268],{},"继承原生 input 全部属性",[236,270,271,276],{},[251,272,273],{},[61,274,275],{},"React.ComponentPropsWithoutRef\u003Ctypeof Link>",[251,277,278],{},"包装第三方组件 props",[236,280,281,286],{},[251,282,283],{},[61,284,285],{},"React.RefObject\u003CHTMLDivElement>",[251,287,288],{},"DOM ref",[49,290,292],{"id":291},"useref","useRef",[54,294,296],{"className":56,"code":295,"language":58,"meta":59,"style":59},"const inputRef = useRef\u003CHTMLInputElement>(null);\ninputRef.current?.focus();\n",[61,297,298,303],{"__ignoreMap":59},[64,299,300],{"class":66,"line":67},[64,301,302],{},"const inputRef = useRef\u003CHTMLInputElement>(null);\n",[64,304,305],{"class":66,"line":73},[64,306,307],{},"inputRef.current?.focus();\n",[49,309,33],{"id":33},[23,311,312,313,316,317,47],{},"使用 ",[61,314,315],{},"React.ChangeEvent\u003CHTMLInputElement>"," 等，避免 ",[61,318,319],{},"any",[49,321,322],{"id":322},"参考文献",[23,324,325],{},"以下链接在编写时均可正常访问：",[230,327,328,338],{},[233,329,330],{},[236,331,332,335],{},[239,333,334],{},"资料",[239,336,337],{},"说明",[246,339,340,353,365],{},[236,341,342,350],{},[251,343,344],{},[43,345,349],{"href":346,"rel":347},"https:\u002F\u002Freact.dev\u002Flearn\u002Ftypescript",[348],"nofollow","React TypeScript 备忘",[251,351,352],{},"英文官方",[236,354,355,362],{},[251,356,357],{},[43,358,361],{"href":359,"rel":360},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@types\u002Freact",[348],"DefinitelyTyped：@types\u002Freact",[251,363,364],{},"类型包",[236,366,367,374],{},[251,368,369],{},[43,370,373],{"href":371,"rel":372},"https:\u002F\u002Fwww.typescriptlang.org\u002Fdocs\u002F",[348],"TypeScript 手册",[251,375,376],{},"语言",[378,379,380],"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":59,"searchDepth":73,"depth":73,"links":382},[383,384,385,386,387,388,389],{"id":51,"depth":73,"text":52},{"id":155,"depth":73,"text":156},{"id":183,"depth":73,"text":183},{"id":228,"depth":73,"text":228},{"id":291,"depth":73,"text":292},{"id":33,"depth":73,"text":33},{"id":322,"depth":73,"text":322},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fframe\u002FReact\u002Ftypescript","knowledge\u002Fknowledge\u002Fbooklet\u002Fframe\u002FReact\u002Ftypescript.md","md",{"items":395},[396,400,404,408,412,416],{"path":397,"title":398,"description":399,"category":10,"score":97},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Frendering","渲染与协调","React 将组件渲染为虚拟 DOM 树，再协调（reconciliation）到浏览器 DOM。理解该过程有助于解释 key、memo 与性能优化。涵盖渲染流程、Fiber、startTransition、Suspense、最佳实践与常见坑。",{"path":401,"title":402,"description":403,"category":10,"score":97},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fproject","工程化","新建 React 项目时，官方与社区主流工具为 Vite；全栈场景常用 Next.js。涵盖 Vite + React、Create React App 现状、Next.js、目录结构、环境变量、部署、最佳实践与常见坑。",{"path":405,"title":406,"description":407,"category":10,"score":97},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftest","测试","React 组件测试推荐 React Testing Library（RTL）：从用户可见行为断言，而非实现细节。运行器常用 Vitest 或 Jest。涵盖安装配置、查询优先级、异步测试、Mock 网络请求、最佳实践与常见坑。",{"path":409,"title":410,"description":411,"category":10,"score":97},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fperformance\u002Fbuild","构建与分包","通过代码分割与构建配置减小首屏 JavaScript 体积。涵盖 React.lazy\u002FSuspense、路由级分割、Tree Shaking、Vite 生产构建、体积分析、最佳实践与常见坑。运行时优化见 runtime。",{"path":413,"title":414,"description":415,"category":10,"score":97},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Feffect","Effect 与副作用","useEffect 用于在组件渲染后执行与外部系统同步的逻辑（请求、订阅、手动改 DOM 等）。涵盖基本用法、依赖数组、适用\u002F不适用场景、useLayoutEffect、最佳实践与常见坑。",{"path":417,"title":418,"description":419,"category":10,"score":97},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fstate","状态管理","React 组件内 state 用 Hooks；跨组件共享状态可选 Context、Redux Toolkit、Zustand 等。见 Context Hook。",{"series":421,"title":12,"items":422,"index":471,"prev":472,"next":473},"booklet\u002Fframe\u002Freact",[423,427,429,432,436,440,442,446,450,452,454,458,462,466,468,470],{"path":424,"title":425,"date":426,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fbasics","React 基础","2020-02-12",{"path":409,"title":410,"date":428,"pinned":15},"2025-07-23",{"path":45,"title":430,"date":431,"pinned":15},"组件与 Props","2020-06-11",{"path":433,"title":434,"date":435,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fcontext","Context","2021-10-16",{"path":437,"title":438,"date":439,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fecology","生态","2023-02-04",{"path":413,"title":414,"date":441,"pinned":15},"2024-10-11",{"path":443,"title":444,"date":445,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fjsx","JSX 与语法","2020-02-29",{"path":447,"title":448,"date":449,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fmemo","Memo、Callback 与 Ref","2021-02-28",{"path":401,"title":402,"date":451,"pinned":15},"2026-05-08",{"path":397,"title":398,"date":453,"pinned":15},"2026-07-10",{"path":455,"title":456,"date":457,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Frouter","路由","2023-09-06",{"path":459,"title":460,"date":461,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fperformance\u002Fruntime","运行时优化","2020-02-05",{"path":463,"title":464,"date":465,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fstate","State 与 Reducer","2021-02-21",{"path":417,"title":418,"date":467,"pinned":15},"2024-02-07",{"path":405,"title":406,"date":469,"pinned":15},"2025-09-26",{"path":7,"title":8,"date":14,"pinned":15},15,{"path":405,"title":406,"date":469,"pinned":15},null]