拆分组件
现在数据、逻辑、界面全挤在 App.jsx 里:功能越多文件越长,改一处都要小心翼翼。React 的解决思路是组件化——把页面拆成一个个"只管一件事"的小组件,再用 props 把数据从父组件传下去。本章为博客首页做一次组件拆分。
为什么要拆分
- 复用:文章卡片在首页、搜索页都要用,抽出来写一次即可。
- 可读:每个文件只负责一小块,看文件名就知道它渲染什么。
- 易维护:想改卡片样式只动一个文件,不影响页面其它部分。
组件本质是函数
函数组件是一个接收 props、返回 JSX 的函数。props 是父组件通过标签属性传进来的数据对象,通常直接解构使用:
// src/components/ArticleCard.jsx
export default function ArticleCard({ post }) { // 解构 props,取出 post
return (
<article className="card">
<h2>{post.title}</h2>
<p>{post.summary}</p>
<span>作者:{post.author}</span>
</article>
);
}
父组件这样传值:<ArticleCard post={posts[0]} />,子组件收到的 props 就是 { post: posts[0] }。
拆分列表组件
循环渲染的"骨架"也值得独立。ArticleList 只关心"给一批文章,铺成列表",内部再逐条引用 ArticleCard:
// src/components/ArticleList.jsx
import ArticleCard from "./ArticleCard";
export default function ArticleList({ posts }) {
if (posts.length === 0) return <p>暂无文章</p>;
return (
<div>
{posts.map((post) => (
<ArticleCard key={post.id} post={post} />
))}
</div>
);
}
App.jsx 里就只剩组合一行:<ArticleList posts={posts} />,页面结构一目了然。
子组件如何通知父组件
props 是单向的:数据只能父传子,子组件不能修改 props。当子组件需要"操作数据"时,父组件把回调函数也作为 props 传下去,由子组件在合适时机调用:
// App.jsx
function deletePost(id) {
setPosts(posts.filter((p) => p.id !== id));
}
<ArticleList posts={posts} onDelete={deletePost} />
// ArticleCard.jsx 里
<button onClick={() => onDelete(post.id)}>删除</button>
数据始终留在父组件,子组件只负责"上报发生了什么",这就是单向数据流。
小结
拆分组件 = 按职责把 JSX 抽成小组件 + 用 props 传递数据与回调。单向数据流让每个组件的数据来源都清晰可查。页面再复杂,也只是这样一层层组合出来的。