主题
Day 2:组件拆分 + props 传递
今天完成什么
- 把三栏布局拆成独立组件
- 理解 props 怎么传递数据
- 让每个组件职责更清晰
接在昨天哪里
昨天所有代码都在 App.tsx 里,现在有:
- 三栏布局(写死的 div)
InfoCardPreview组件(写死的数据)
今天要把布局拆出来,为明天引入状态做准备。
概念解释
为什么要拆组件
当前 App.tsx 有 70 多行,还没加配置表单就已经很长了。
拆组件的好处:
- 职责单一:一个组件只做一件事
- 可读性:主组件只负责组织,不关心细节
- 复用性:相同逻辑可以复用
什么是 props
props 是父组件传给子组件的数据:
tsx
// 父组件
<InfoCardPreview title="客户资料" />
// 子组件
function InfoCardPreview(props: { title: string }) {
return <h3>{props.title}</h3>;
}props 是只读的,子组件不能修改 props。
Props 解构
可以直接解构 props:
tsx
function InfoCardPreview({ title }: { title: string }) {
return <h3>{title}</h3>;
}这样更简洁,不用每次写 props.title。
动手实现
第 1 步:拆出组件列表侧边栏
新建 src/components/ComponentSidebar.tsx:
tsx
function ComponentSidebar() {
return (
<div style={{
flex: '0 0 200px',
backgroundColor: '#f5f5f5',
padding: '20px',
borderRight: '1px solid #ddd'
}}>
<h3>组件列表</h3>
<div style={{
padding: '10px',
backgroundColor: '#fff',
border: '1px solid #ddd',
borderRadius: '4px',
cursor: 'pointer'
}}>
InfoCard
</div>
</div>
);
}
export default ComponentSidebar;第 2 步:拆出配置面板
新建 src/components/ConfigPanel.tsx:
tsx
function ConfigPanel() {
return (
<div style={{
flex: '1',
padding: '20px',
overflowY: 'auto'
}}>
<h2>配置面板</h2>
<p style={{ color: '#999' }}>后续章节会在这里加表单</p>
</div>
);
}
export default ConfigPanel;第 3 步:拆出预览面板
新建 src/components/PreviewPanel.tsx:
tsx
import InfoCardPreview from './InfoCardPreview';
function PreviewPanel() {
return (
<div style={{
flex: '1',
padding: '20px',
backgroundColor: '#fafafa',
overflowY: 'auto'
}}>
<h2 style={{ marginTop: 0 }}>预览</h2>
<InfoCardPreview />
</div>
);
}
export default PreviewPanel;第 4 步:创建主配置页组件
新建 src/components/LowCodeConfigPage.tsx:
tsx
import ComponentSidebar from './ComponentSidebar';
import ConfigPanel from './ConfigPanel';
import PreviewPanel from './PreviewPanel';
function LowCodeConfigPage() {
return (
<div style={{
display: 'flex',
height: '100vh',
fontFamily: 'sans-serif'
}}>
<ComponentSidebar />
<ConfigPanel />
<PreviewPanel />
</div>
);
}
export default LowCodeConfigPage;第 5 步:简化 App.tsx
修改 src/App.tsx:
tsx
import LowCodeConfigPage from './components/LowCodeConfigPage';
function App() {
return <LowCodeConfigPage />;
}
export default App;现在 App.tsx 只有 7 行,清爽多了。
第 6 步:给 PreviewPanel 加 props
修改 src/components/PreviewPanel.tsx,让它能接收一个标题:
tsx
import InfoCardPreview from './InfoCardPreview';
type PreviewPanelProps = {
title?: string;
};
function PreviewPanel({ title = '预览' }: PreviewPanelProps) {
return (
<div style={{
flex: '1',
padding: '20px',
backgroundColor: '#fafafa',
overflowY: 'auto'
}}>
<h2 style={{ marginTop: 0 }}>{title}</h2>
<InfoCardPreview />
</div>
);
}
export default PreviewPanel;第 7 步:从父组件传 props
修改 src/components/LowCodeConfigPage.tsx:
tsx
import ComponentSidebar from './ComponentSidebar';
import ConfigPanel from './ConfigPanel';
import PreviewPanel from './PreviewPanel';
function LowCodeConfigPage() {
return (
<div style={{
display: 'flex',
height: '100vh',
fontFamily: 'sans-serif'
}}>
<ComponentSidebar />
<ConfigPanel />
<PreviewPanel title="实时预览" />
</div>
);
}
export default LowCodeConfigPage;当前目录结构
text
src/
├─ App.tsx
├─ main.tsx
└─ components/
├─ LowCodeConfigPage.tsx
├─ ComponentSidebar.tsx
├─ ConfigPanel.tsx
├─ PreviewPanel.tsx
└─ InfoCardPreview.tsx运行效果
保存后浏览器自动刷新,界面和昨天一模一样,但代码结构更清晰了。
右侧标题从「预览」变成了「实时预览」,这是 props 传递的效果。
常见错误
1. 忘记定义 props 类型
tsx
// ❌ 错误
function PreviewPanel({ title }) { ... }
// ✅ 正确
function PreviewPanel({ title }: { title: string }) { ... }TypeScript 项目必须给 props 加类型。
2. 在子组件里修改 props
tsx
// ❌ 错误
function PreviewPanel({ title }: { title: string }) {
title = '新标题'; // props 是只读的
return <h2>{title}</h2>;
}
// ✅ 正确
// props 只能读,不能改如果想改数据,要用 state(明天会讲)。
3. 解构时漏掉类型
tsx
// ❌ 错误
type Props = { title: string };
function PreviewPanel({ title }) { ... } // 没关联上类型
// ✅ 正确
type Props = { title: string };
function PreviewPanel({ title }: Props) { ... }4. 可选 props 没给默认值
tsx
// ❌ 可能出错
function PreviewPanel({ title }: { title?: string }) {
return <h2>{title}</h2>; // title 可能是 undefined
}
// ✅ 正确
function PreviewPanel({ title = '预览' }: { title?: string }) {
return <h2>{title}</h2>;
}动手改一改
- 给
ComponentSidebar加一个 propscomponents,类型是string[],用来显示组件列表 - 在
LowCodeConfigPage里传components={['InfoCard', 'StatCard']} - 用
map把数组渲染成列表
提示:
tsx
{components.map(name => (
<div key={name}>...</div>
))}验收清单
- [ ] 项目能正常启动,界面和昨天一样
- [ ]
App.tsx只有一行<LowCodeConfigPage /> - [ ]
src/components/下有 5 个组件文件 - [ ] 右侧预览区标题显示「实时预览」
- [ ] 能解释什么是 props,props 是只读的
- [ ] 完成「动手改一改」的练习
今日记录
今天跑通:
- 把三栏布局拆成 4 个独立组件
- props 传递数据
- TypeScript 定义 props 类型
现在能解释:
- 为什么要拆组件
- props 怎么传递
- 解构 props 的写法
- 可选 props 的默认值
明天先做:
- 定义
InfoCardConfig类型 - 用
useState管理配置状态 - 让
InfoCardPreview从 props 读配置,而不是写死数据
留给明天的接口
当前组件结构:
text
LowCodeConfigPage(主组件)
├─ ComponentSidebar
├─ ConfigPanel
└─ PreviewPanel
└─ InfoCardPreview(数据还是写死的)明天要在 LowCodeConfigPage 里用 useState 管理一个 config 对象,传给 InfoCardPreview。
进行中