📖 核心概念
- React哲学:UI = f(state)
- JSX语法与表达式
- 函数组件与Props
- 组件组合与children
- 条件渲染与列表渲染
- React开发者工具
💻 代码实现
React组件基础
✅ tsx
// UserCard.tsx - 可复用组件
import { type ReactNode } from 'react';
interface UserCardProps {
name: string;
avatar: string;
bio?: string;
tags?: string[];
children?: ReactNode;
variant?: 'default' | 'compact';
}
export function UserCard({
name, avatar, bio, tags = [], children, variant = 'default',
}: UserCardProps) {
const isCompact = variant === 'compact';
return (
<article className={\`user-card \${isCompact ? 'compact' : ''}\`}>
<img src={avatar} alt={name} className="avatar" />
<div className="info">
<h3>{name}</h3>
{!isCompact && bio && <p className="bio">{bio}</p>}
{tags.length > 0 && (
<div className="tags">
{tags.map(tag => (
<span key={tag} className="tag">#{tag}</span>
))}
</div>
)}
{children && <div className="card-footer">{children}</div>}
</div>
</article>
);
}
// App.tsx - 组合使用
import { UserCard } from './UserCard';
function App() {
const users = [
{ id: 1, name: '张三', avatar: '/zhang.jpg', bio: '前端工程师', tags: ['React', 'TypeScript'] },
{ id: 2, name: '李四', avatar: '/li.jpg', bio: '全栈开发', tags: ['Vue', 'Node.js'] },
{ id: 3, name: '王五', avatar: '/wang.jpg', tags: ['设计'] },
];
return (
<div className="app">
<h1>用户列表</h1>
{/* 列表渲染 */}
{users.map(user => (
<UserCard key={user.id} {...user}>
<button onClick={() => console.log(\`关注 \${user.name}\`)}>
关注
</button>
</UserCard>
))}
{/* 紧凑模式 */}
<h2>推荐关注</h2>
{users.slice(0, 2).map(user => (
<UserCard key={user.id} {...user} variant="compact" />
))}
</div>
);
}
组件模式与组合
✅ tsx
// Layout组件 - 组合模式
function Layout({ header, sidebar, children, footer }: {
header: ReactNode;
sidebar?: ReactNode;
children: ReactNode;
footer?: ReactNode;
}) {
return (
<div className="layout">
<header className="layout-header">{header}</header>
<div className="layout-body">
{sidebar && <aside className="layout-sidebar">{sidebar}</aside>}
<main className="layout-content">{children}</main>
</div>
{footer && <footer className="layout-footer">{footer}</footer>}
</div>
);
}
// Render Props模式
interface DataFetcherProps<T> {
url: string;
render: (state: { data: T | null; loading: boolean; error: Error | null }) => ReactNode;
}
function DataFetcher<T>({ url, render }: DataFetcherProps<T>) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
fetch(url)
.then(r => r.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);
return <>{render({ data, loading, error })}</>;
}
// 使用Render Props
<DataFetcher<{ name: string }[]> url="/api/users" render={({ data, loading, error }) => {
if (loading) return <Spinner />;
if (error) return <Error message={error.message} />;
return <UserList users={data!} />;
}} />
// 条件渲染技巧
function StatusBadge({ status }: { status: 'active' | 'inactive' | 'pending' }) {
return (
<span className={\`badge badge-\${status}\`}>
{{ active: '✅ 活跃', inactive: '❌ 停用', pending: '⏳ 待审核' }[status]}
</span>
);
}
// 短路渲染
function Notification({ count }: { count: number }) {
return (
<div className="notification">
🔔 {count > 0 && <span className="badge">{count > 99 ? '99+' : count}</span>}
</div>
);
}
🎯 练习任务
- 1 创建一个可复用的Card组件,支持多种变体
- 2 实现一个Layout组件,支持header/sidebar/content/footer组合
- 3 用条件渲染实现一个多功能状态展示组件
- 4 设计一个组件库的基础组件体系(Button/Input/Card/Modal)
🏆 成就解锁
组件建筑师 — 掌握React组件化思维,构建可复用的UI组件