[{"data":1,"prerenderedAt":215},["ShallowReactive",2],{"article-vite-react-project":3,"related-articles":114},{"id":4,"title":5,"body":6,"categoryLabel":98,"categorySlug":99,"description":100,"extension":101,"featured":102,"meta":103,"navigation":104,"path":105,"publishedAt":106,"readingMinutes":49,"seo":107,"stem":108,"tags":109,"__hash__":113},"blog\u002Fblog\u002Fvite-react-project.md","用 Vite 创建一个 React + TypeScript 小项目",{"type":7,"value":8,"toc":94},"minimark",[9,13,17,53,56,59,87,90],[10,11,12],"p",{},"Vite 提供了 React 和 TypeScript 起步模板，适合快速开始一个前端练习项目。",[14,15,16],"h2",{"id":16},"创建项目",[18,19,24],"pre",{"className":20,"code":21,"language":22,"meta":23,"style":23},"language-sh shiki shiki-themes github-light-high-contrast","npm create vite@latest my-react-app -- --template react-ts\ncd my-react-app\nnpm install\nnpm run dev\n","sh","",[25,26,27,35,41,47],"code",{"__ignoreMap":23},[28,29,32],"span",{"class":30,"line":31},"line",1,[28,33,34],{},"npm create vite@latest my-react-app -- --template react-ts\n",[28,36,38],{"class":30,"line":37},2,[28,39,40],{},"cd my-react-app\n",[28,42,44],{"class":30,"line":43},3,[28,45,46],{},"npm install\n",[28,48,50],{"class":30,"line":49},4,[28,51,52],{},"npm run dev\n",[10,54,55],{},"命令会创建项目目录、安装依赖并启动本地开发服务。实际命令可能随 Vite 版本调整，创建时以终端提示为准。",[14,57,58],{"id":58},"先看哪些文件",[60,61,62,69,75,81],"ul",{},[63,64,65,68],"li",{},[25,66,67],{},"src\u002F","：页面与组件代码。",[63,70,71,74],{},[25,72,73],{},"package.json","：依赖和常用命令。",[63,76,77,80],{},[25,78,79],{},"tsconfig.json","：TypeScript 编译选项。",[63,82,83,86],{},[25,84,85],{},"vite.config.ts","：Vite 插件和开发服务器设置。",[10,88,89],{},"一个小练习开始时不必急着增加很多工具。先熟悉开发、构建和类型检查，再按项目需要添加能力。",[91,92,93],"style",{},"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);}",{"title":23,"searchDepth":37,"depth":37,"links":95},[96,97],{"id":16,"depth":37,"text":16},{"id":58,"depth":37,"text":58},"开发工具","tools","记录从初始化模板到启动开发服务器的基础步骤，以及几个值得先检查的文件。","md",false,{},true,"\u002Fblog\u002Fvite-react-project","2026-06-12",{"title":5,"description":100},"blog\u002Fvite-react-project",[110,111,112],"Vite","React","TypeScript","JoVhgmBL3ttzcLRgwU8U1QWqewWAybYWCb464cXenQw",[115,127,137,148,156,164,172,180,188,197,205,213],{"id":116,"path":117,"title":118,"description":119,"categorySlug":120,"categoryLabel":121,"publishedAt":122,"readingMinutes":49,"featured":104,"tags":123},"blog\u002Fblog\u002Fcss-grid-cards.md","\u002Fblog\u002Fcss-grid-cards","用 CSS Grid 排列自适应卡片","使用 repeat、minmax 和 auto-fit，让卡片列数随容器宽度自然变化。","styles","页面与样式","2026-09-10",[124,125,126],"CSS","Grid","页面布局",{"id":128,"path":129,"title":130,"description":131,"categorySlug":120,"categoryLabel":121,"publishedAt":132,"readingMinutes":133,"featured":102,"tags":134},"blog\u002Fblog\u002Fmobile-layout-checklist.md","\u002Fblog\u002Fmobile-layout-checklist","做移动端页面适配时的检查笔记","从内容宽度、触控区域、文字换行和键盘焦点几个方面检查窄屏体验。","2026-08-20",5,[124,135,136],"响应式","可访问性",{"id":138,"path":139,"title":140,"description":141,"categorySlug":142,"categoryLabel":111,"publishedAt":143,"readingMinutes":144,"featured":104,"tags":145},"blog\u002Fblog\u002Freact-controlled-form.md","\u002Fblog\u002Freact-controlled-form","React 受控表单：从一个输入框开始","用一个简单的姓名输入框，理解 value、onChange 与 React state 之间的关系。","react","2026-09-18",6,[111,146,147],"表单","学习笔记",{"id":149,"path":150,"title":151,"description":152,"categorySlug":142,"categoryLabel":111,"publishedAt":153,"readingMinutes":49,"featured":102,"tags":154},"blog\u002Fblog\u002Freact-list-keys.md","\u002Fblog\u002Freact-list-keys","React 列表渲染里的 key 有什么用","通过稳定的 key 帮助 React 识别列表项目，避免用数组下标造成的状态错位。","2026-08-12",[111,155,147],"列表",{"id":157,"path":158,"title":159,"description":160,"categorySlug":142,"categoryLabel":111,"publishedAt":161,"readingMinutes":133,"featured":102,"tags":162},"blog\u002Fblog\u002Freact-props-and-state.md","\u002Fblog\u002Freact-props-and-state","React 组件里的 Props 和 State","用一个简单的信息卡片区分外部传入的数据和组件内部会变化的数据。","2026-08-28",[111,163,147],"组件",{"id":165,"path":166,"title":167,"description":168,"categorySlug":142,"categoryLabel":111,"publishedAt":169,"readingMinutes":133,"featured":102,"tags":170},"blog\u002Fblog\u002Freact-small-components.md","\u002Fblog\u002Freact-small-components","把重复的界面拆成小组件","从重复的按钮和卡片开始，认识组件拆分的几个简单信号。","2026-07-16",[111,163,171],"练习记录",{"id":173,"path":174,"title":175,"description":176,"categorySlug":142,"categoryLabel":111,"publishedAt":177,"readingMinutes":144,"featured":102,"tags":178},"blog\u002Fblog\u002Freact-use-effect-notes.md","\u002Fblog\u002Freact-use-effect-notes","React useEffect 的依赖和清理","整理 useEffect 何时运行，以及订阅和定时器为什么需要清理。","2026-06-30",[111,179,147],"useEffect",{"id":181,"path":182,"title":183,"description":184,"categorySlug":142,"categoryLabel":111,"publishedAt":185,"readingMinutes":49,"featured":102,"tags":186},"blog\u002Fblog\u002Freact-use-state-practice.md","\u002Fblog\u002Freact-use-state-practice","用 useState 管理一个简单的计数交互","从加一和重置两个操作，熟悉 React state 的声明与更新方式。","2026-07-30",[111,187,171],"useState",{"id":189,"path":190,"title":191,"description":192,"categorySlug":193,"categoryLabel":112,"publishedAt":194,"readingMinutes":133,"featured":104,"tags":195},"blog\u002Fblog\u002Ftypescript-component-props.md","\u002Fblog\u002Ftypescript-component-props","给 React 组件的 Props 添加 TypeScript 类型","用必填属性和可选属性描述组件接口，让使用方式在编辑器里更清晰。","typescript","2026-09-02",[112,111,196],"类型",{"id":198,"path":199,"title":200,"description":201,"categorySlug":193,"categoryLabel":112,"publishedAt":202,"readingMinutes":133,"featured":104,"tags":203},"blog\u002Fblog\u002Ftypescript-narrowing.md","\u002Fblog\u002Ftypescript-narrowing","TypeScript 类型收窄入门","使用 typeof 和条件判断缩小联合类型的范围，让后续代码更安全。","2026-09-25",[112,204,147],"类型收窄",{"id":206,"path":207,"title":208,"description":209,"categorySlug":193,"categoryLabel":112,"publishedAt":210,"readingMinutes":49,"featured":102,"tags":211},"blog\u002Fblog\u002Ftypescript-union-status.md","\u002Fblog\u002Ftypescript-union-status","用联合类型描述请求状态","把加载、成功和失败等状态限制在明确的集合里，减少拼写错误和遗漏分支。","2026-08-04",[112,212,147],"联合类型",{"id":4,"path":105,"title":5,"description":100,"categorySlug":99,"categoryLabel":98,"publishedAt":106,"readingMinutes":49,"featured":102,"tags":214},[110,111,112],1792674168733]