[{"data":1,"prerenderedAt":357},["ShallowReactive",2],{"article-react-props-and-state":3,"related-articles":257},{"id":4,"title":5,"body":6,"categoryLabel":243,"categorySlug":244,"description":245,"extension":246,"featured":247,"meta":248,"navigation":82,"path":249,"publishedAt":250,"readingMinutes":79,"seo":251,"stem":252,"tags":253,"__hash__":256},"blog\u002Fblog\u002Freact-props-and-state.md","React 组件里的 Props 和 State",{"type":7,"value":8,"toc":238},"minimark",[9,13,18,179,182,186,189,228,231,234],[10,11,12],"p",{},"React 组件常用 Props 接收外部数据，用 State 保存组件内部会变化的数据。先把两者分开理解，页面状态会更容易追踪。",[14,15,17],"h2",{"id":16},"props-由使用者传入","Props 由使用者传入",[19,20,25],"pre",{"className":21,"code":22,"language":23,"meta":24,"style":24},"language-tsx shiki shiki-themes github-light-high-contrast","type ProfileCardProps = {\n  name: string\n  description: string\n}\n\nfunction ProfileCard({ name, description }: ProfileCardProps) {\n  return \u003Csection>\u003Ch2>{name}\u003C\u002Fh2>\u003Cp>{description}\u003C\u002Fp>\u003C\u002Fsection>\n}\n","tsx","",[26,27,28,48,61,71,77,84,116,174],"code",{"__ignoreMap":24},[29,30,33,37,41,44],"span",{"class":31,"line":32},"line",1,[29,34,36],{"class":35},"sTJeM","type",[29,38,40],{"class":39},"sV4o_"," ProfileCardProps",[29,42,43],{"class":35}," =",[29,45,47],{"class":46},"sigWx"," {\n",[29,49,51,54,57],{"class":31,"line":50},2,[29,52,53],{"class":39},"  name",[29,55,56],{"class":35},":",[29,58,60],{"class":59},"sacAq"," string\n",[29,62,64,67,69],{"class":31,"line":63},3,[29,65,66],{"class":39},"  description",[29,68,56],{"class":35},[29,70,60],{"class":59},[29,72,74],{"class":31,"line":73},4,[29,75,76],{"class":46},"}\n",[29,78,80],{"class":31,"line":79},5,[29,81,83],{"emptyLinePlaceholder":82},true,"\n",[29,85,87,90,94,97,100,103,106,109,111,113],{"class":31,"line":86},6,[29,88,89],{"class":35},"function",[29,91,93],{"class":92},"s3dhs"," ProfileCard",[29,95,96],{"class":46},"({ ",[29,98,99],{"class":39},"name",[29,101,102],{"class":46},", ",[29,104,105],{"class":39},"description",[29,107,108],{"class":46}," }",[29,110,56],{"class":35},[29,112,40],{"class":39},[29,114,115],{"class":46},") {\n",[29,117,119,122,125,129,132,134,137,140,142,145,148,150,152,154,156,158,160,162,164,166,169,171],{"class":31,"line":118},7,[29,120,121],{"class":35},"  return",[29,123,124],{"class":46}," \u003C",[29,126,128],{"class":127},"s742_","section",[29,130,131],{"class":46},">\u003C",[29,133,14],{"class":127},[29,135,136],{"class":46},">",[29,138,139],{"class":35},"{",[29,141,99],{"class":46},[29,143,144],{"class":35},"}",[29,146,147],{"class":46},"\u003C\u002F",[29,149,14],{"class":127},[29,151,131],{"class":46},[29,153,10],{"class":127},[29,155,136],{"class":46},[29,157,139],{"class":35},[29,159,105],{"class":46},[29,161,144],{"class":35},[29,163,147],{"class":46},[29,165,10],{"class":127},[29,167,168],{"class":46},">\u003C\u002F",[29,170,128],{"class":127},[29,172,173],{"class":46},">\n",[29,175,177],{"class":31,"line":176},8,[29,178,76],{"class":46},[10,180,181],{},"父组件可以通过属性传入不同内容。子组件读取 Props 来展示信息，不应该直接修改传进来的值。",[14,183,185],{"id":184},"state-保存交互状态","State 保存交互状态",[10,187,188],{},"像展开\u002F收起、输入框内容这样的变化，可以放在 state 里。更新 state 后，React 会重新渲染相关界面。",[19,190,192],{"className":21,"code":191,"language":23,"meta":24,"style":24},"const [expanded, setExpanded] = useState(false)\n",[26,193,194],{"__ignoreMap":24},[29,195,196,199,202,205,207,210,213,216,219,222,225],{"class":31,"line":32},[29,197,198],{"class":35},"const",[29,200,201],{"class":46}," [",[29,203,204],{"class":59},"expanded",[29,206,102],{"class":46},[29,208,209],{"class":59},"setExpanded",[29,211,212],{"class":46},"] ",[29,214,215],{"class":35},"=",[29,217,218],{"class":92}," useState",[29,220,221],{"class":46},"(",[29,223,224],{"class":59},"false",[29,226,227],{"class":46},")\n",[14,229,230],{"id":230},"怎么选择",[10,232,233],{},"如果值由父组件决定，用 Props；如果值由当前组件的交互维护，用 State。状态需要被多个组件共享时，可以再考虑把它提升到共同的父组件。",[235,236,237],"style",{},"html pre.shiki code .sTJeM, html code.shiki .sTJeM{--shiki-default:#A0111F}html pre.shiki code .sV4o_, html code.shiki .sV4o_{--shiki-default:#702C00}html pre.shiki code .sigWx, html code.shiki .sigWx{--shiki-default:#0E1116}html pre.shiki code .sacAq, html code.shiki .sacAq{--shiki-default:#023B95}html pre.shiki code .s3dhs, html code.shiki .s3dhs{--shiki-default:#622CBC}html pre.shiki code .s742_, html code.shiki .s742_{--shiki-default:#024C1A}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":24,"searchDepth":50,"depth":50,"links":239},[240,241,242],{"id":16,"depth":50,"text":17},{"id":184,"depth":50,"text":185},{"id":230,"depth":50,"text":230},"React","react","用一个简单的信息卡片区分外部传入的数据和组件内部会变化的数据。","md",false,{},"\u002Fblog\u002Freact-props-and-state","2026-08-28",{"title":5,"description":245},"blog\u002Freact-props-and-state",[243,254,255],"组件","学习笔记","WCIzi-x0wGeD3XJNlwVCZfcAojnsoLrC4265D7Idgtk",[258,270,279,287,295,297,305,313,321,331,339,347],{"id":259,"path":260,"title":261,"description":262,"categorySlug":263,"categoryLabel":264,"publishedAt":265,"readingMinutes":73,"featured":82,"tags":266},"blog\u002Fblog\u002Fcss-grid-cards.md","\u002Fblog\u002Fcss-grid-cards","用 CSS Grid 排列自适应卡片","使用 repeat、minmax 和 auto-fit，让卡片列数随容器宽度自然变化。","styles","页面与样式","2026-09-10",[267,268,269],"CSS","Grid","页面布局",{"id":271,"path":272,"title":273,"description":274,"categorySlug":263,"categoryLabel":264,"publishedAt":275,"readingMinutes":79,"featured":247,"tags":276},"blog\u002Fblog\u002Fmobile-layout-checklist.md","\u002Fblog\u002Fmobile-layout-checklist","做移动端页面适配时的检查笔记","从内容宽度、触控区域、文字换行和键盘焦点几个方面检查窄屏体验。","2026-08-20",[267,277,278],"响应式","可访问性",{"id":280,"path":281,"title":282,"description":283,"categorySlug":244,"categoryLabel":243,"publishedAt":284,"readingMinutes":86,"featured":82,"tags":285},"blog\u002Fblog\u002Freact-controlled-form.md","\u002Fblog\u002Freact-controlled-form","React 受控表单：从一个输入框开始","用一个简单的姓名输入框，理解 value、onChange 与 React state 之间的关系。","2026-09-18",[243,286,255],"表单",{"id":288,"path":289,"title":290,"description":291,"categorySlug":244,"categoryLabel":243,"publishedAt":292,"readingMinutes":73,"featured":247,"tags":293},"blog\u002Fblog\u002Freact-list-keys.md","\u002Fblog\u002Freact-list-keys","React 列表渲染里的 key 有什么用","通过稳定的 key 帮助 React 识别列表项目，避免用数组下标造成的状态错位。","2026-08-12",[243,294,255],"列表",{"id":4,"path":249,"title":5,"description":245,"categorySlug":244,"categoryLabel":243,"publishedAt":250,"readingMinutes":79,"featured":247,"tags":296},[243,254,255],{"id":298,"path":299,"title":300,"description":301,"categorySlug":244,"categoryLabel":243,"publishedAt":302,"readingMinutes":79,"featured":247,"tags":303},"blog\u002Fblog\u002Freact-small-components.md","\u002Fblog\u002Freact-small-components","把重复的界面拆成小组件","从重复的按钮和卡片开始，认识组件拆分的几个简单信号。","2026-07-16",[243,254,304],"练习记录",{"id":306,"path":307,"title":308,"description":309,"categorySlug":244,"categoryLabel":243,"publishedAt":310,"readingMinutes":86,"featured":247,"tags":311},"blog\u002Fblog\u002Freact-use-effect-notes.md","\u002Fblog\u002Freact-use-effect-notes","React useEffect 的依赖和清理","整理 useEffect 何时运行，以及订阅和定时器为什么需要清理。","2026-06-30",[243,312,255],"useEffect",{"id":314,"path":315,"title":316,"description":317,"categorySlug":244,"categoryLabel":243,"publishedAt":318,"readingMinutes":73,"featured":247,"tags":319},"blog\u002Fblog\u002Freact-use-state-practice.md","\u002Fblog\u002Freact-use-state-practice","用 useState 管理一个简单的计数交互","从加一和重置两个操作，熟悉 React state 的声明与更新方式。","2026-07-30",[243,320,304],"useState",{"id":322,"path":323,"title":324,"description":325,"categorySlug":326,"categoryLabel":327,"publishedAt":328,"readingMinutes":79,"featured":82,"tags":329},"blog\u002Fblog\u002Ftypescript-component-props.md","\u002Fblog\u002Ftypescript-component-props","给 React 组件的 Props 添加 TypeScript 类型","用必填属性和可选属性描述组件接口，让使用方式在编辑器里更清晰。","typescript","TypeScript","2026-09-02",[327,243,330],"类型",{"id":332,"path":333,"title":334,"description":335,"categorySlug":326,"categoryLabel":327,"publishedAt":336,"readingMinutes":79,"featured":82,"tags":337},"blog\u002Fblog\u002Ftypescript-narrowing.md","\u002Fblog\u002Ftypescript-narrowing","TypeScript 类型收窄入门","使用 typeof 和条件判断缩小联合类型的范围，让后续代码更安全。","2026-09-25",[327,338,255],"类型收窄",{"id":340,"path":341,"title":342,"description":343,"categorySlug":326,"categoryLabel":327,"publishedAt":344,"readingMinutes":73,"featured":247,"tags":345},"blog\u002Fblog\u002Ftypescript-union-status.md","\u002Fblog\u002Ftypescript-union-status","用联合类型描述请求状态","把加载、成功和失败等状态限制在明确的集合里，减少拼写错误和遗漏分支。","2026-08-04",[327,346,255],"联合类型",{"id":348,"path":349,"title":350,"description":351,"categorySlug":352,"categoryLabel":353,"publishedAt":354,"readingMinutes":73,"featured":247,"tags":355},"blog\u002Fblog\u002Fvite-react-project.md","\u002Fblog\u002Fvite-react-project","用 Vite 创建一个 React + TypeScript 小项目","记录从初始化模板到启动开发服务器的基础步骤，以及几个值得先检查的文件。","tools","开发工具","2026-06-12",[356,243,327],"Vite",1792674168123]