函数组件与类组件详解
组件定义:组件是React应用的基本构建块。每个组件都是一个独立的、可复用的代码单元,负责渲染UI的一部分。
函数组件:使用JavaScript函数定义的组件。这是React推荐的组件定义方式,特别是配合Hooks使用。
// 最简单的函数组件
function Welcome() {
return <h1>Hello, React!</h1>;
}
// 使用箭头函数
const Welcome = () => {
return <h1>Hello, React!</h1>;
};
// 隐式返回(单行表达式)
const Welcome = () => <h1>Hello, React!</h1>;
// 接收props参数
function UserCard(props) {
return (
<div className="user-card">
<h2>{props.name}</h2>
<p>年龄: {props.age}</p>
<p>邮箱: {props.email}</p>
</div>
);
}
// 使用解构语法(推荐)
function UserCard({ name, age, email }) {
return (
<div className="user-card">
<h2>{name}</h2>
<p>年龄: {age}</p>
<p>邮箱: {email}</p>
</div>
);
}
// 使用组件
function App() {
return (
<UserCard
name="张三"
age={25}
email="zhangsan@example.com"
/>
);
}
注意:类组件是React的传统写法,现在推荐使用函数组件配合Hooks。但了解类组件有助于理解React的发展历程。
// 类组件定义
class Welcome extends React.Component {
render() {
return <h1>Hello, React!</h1>;
}
}
// 带Props的类组件
class UserCard extends React.Component {
render() {
const { name, age, email } = this.props;
return (
<div className="user-card">
<h2>{name}</h2>
<p>年龄: {age}</p>
<p>邮箱: {email}</p>
</div>
);
}
}
Props概念:Props(属性)是组件之间传递数据的方式。Props是只读的,组件不能修改自己的Props。
// 父组件传递Props
function App() {
const user = {
name: '李四',
age: 30,
email: 'lisi@example.com',
avatar: 'avatar.jpg'
};
return (
<div>
<UserCard
name={user.name}
age={user.age}
email={user.email}
avatar={user.avatar}
/>
{/* 使用展开运算符传递所有属性 */}
<UserCard {...user} />
</div>
);
}
// 子组件接收Props
function UserCard({ name, age, email, avatar }) {
return (
<div className="user-card">
<img src={avatar} alt={name} />
<h2>{name}</h2>
<p>年龄: {age}</p>
<p>邮箱: {email}</p>
</div>
);
}
// 函数组件的默认Props
function Button({ text, color = 'blue', size = 'medium' }) {
return (
<button
style={{
backgroundColor: color,
padding: size === 'large' ? '15px 30px' : '10px 20px'
}}
>
{text}
</button>
);
}
// 类组件的默认Props
class Button extends React.Component {
static defaultProps = {
color: 'blue',
size: 'medium'
};
render() {
const { text, color, size } = this.props;
// ...
}
}
// 使用默认Props
<Button text="点击我" /> // 使用默认颜色和大小
<Button text="点击我" color="red" size="large" /> // 自定义属性
组合模式:React推崇组合而非继承。通过组合简单的组件来构建复杂的UI。
// 容器组件
function Card({ title, children }) {
return (
<div className="card">
<h3>{title}</h3>
<div className="card-content">
{children}
</div>
</div>
);
}
// 使用children属性
function App() {
return (
<Card title="用户信息">
<p>姓名: 张三</p>
<p>年龄: 25</p>
<button>查看详情</button>
</Card>
);
}
// 通用组件
function Dialog({ title, message, onConfirm }) {
return (
<div className="dialog">
<h3>{title}</h3>
<p>{message}</p>
<button onClick={onConfirm}>确认</button>
</div>
);
}
// 特例组件
function WelcomeDialog() {
return (
<Dialog
title="欢迎"
message="欢迎使用我们的应用!"
onConfirm={() => alert('欢迎!')}
/>
);
}
function ErrorDialog({ message }) {
return (
<Dialog
title="错误"
message={message}
onConfirm={() => console.log('错误已确认')}
/>
);
}
function Counter() {
const [count, setCount] = useState(0);
const handleIncrement = () => {
setCount(count + 1);
};
const handleDecrement = () => {
setCount(count - 1);
};
const handleReset = () => {
setCount(0);
};
return (
<div>
<h2>计数器: {count}</h2>
<button onClick={handleIncrement}>+1</button>
<button onClick={handleDecrement}>-1</button>
<button onClick={handleReset}>重置</button>
</div>
);
}
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: '学习React', completed: false },
{ id: 2, text: '写代码', completed: true }
]);
const handleToggle = (todoId) => {
setTodos(todos.map(todo =>
todo.id === todoId
? { ...todo, completed: !todo.completed }
: todo
));
};
const handleDelete = (todoId) => {
setTodos(todos.filter(todo => todo.id !== todoId));
};
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<span
style={{
textDecoration: todo.completed ? 'line-through' : 'none'
}}
onClick={() => handleToggle(todo.id)}
>
{todo.text}
</span>
<button onClick={() => handleDelete(todo.id)}>
删除
</button>
</li>
))}
</ul>
);
}
任务:创建一个可复用的Modal组件
要求:
// 参考答案
function Modal({ title, children, onClose, isOpen }) {
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={e => e.stopPropagation()}>
<div className="modal-header">
<h3>{title}</h3>
<button onClick={onClose}>×</button>
</div>
<div className="modal-body">
{children}
</div>
</div>
</div>
);
}
function ConfirmModal({ message, onConfirm, onCancel, isOpen }) {
return (
<Modal title="确认操作" isOpen={isOpen} onClose={onCancel}>
<p>{message}</p>
<div style={{display: 'flex', gap: '10px', justifyContent: 'flex-end'}}>
<button onClick={onCancel}>取消</button>
<button onClick={onConfirm}>确认</button>
</div>
</Modal>
);
}
function InfoModal({ message, isOpen, onClose }) {
return (
<Modal title="信息" isOpen={isOpen} onClose={onClose}>
<p>{message}</p>
<button onClick={onClose}>知道了</button>
</Modal>
);
}