← 返回目录 | 下一课:State状态管理 →

第3课: 组件基础

函数组件与类组件详解

🎯 学习目标

1. 组件的基本概念

组件定义:组件是React应用的基本构建块。每个组件都是一个独立的、可复用的代码单元,负责渲染UI的一部分。

组件层级结构

App组件
Header
Main
Footer
Nav
Content
Sidebar

2. 函数组件

函数组件:使用JavaScript函数定义的组件。这是React推荐的组件定义方式,特别是配合Hooks使用。

2.1 基本函数组件

// 最简单的函数组件
function Welcome() {
    return <h1>Hello, React!</h1>;
}

// 使用箭头函数
const Welcome = () => {
    return <h1>Hello, React!</h1>;
};

// 隐式返回(单行表达式)
const Welcome = () => <h1>Hello, React!</h1>;

2.2 带Props的函数组件

// 接收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" 
        />
    );
}

3. 类组件

注意:类组件是React的传统写法,现在推荐使用函数组件配合Hooks。但了解类组件有助于理解React的发展历程。

3.1 基本类组件

// 类组件定义
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>
        );
    }
}

4. Props详解

Props概念:Props(属性)是组件之间传递数据的方式。Props是只读的,组件不能修改自己的Props。

4.1 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>
    );
}

4.2 默认Props

// 函数组件的默认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" />  // 自定义属性

5. 组件组合

组合模式:React推崇组合而非继承。通过组合简单的组件来构建复杂的UI。

5.1 包含关系

// 容器组件
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>
    );
}

5.2 特例关系

// 通用组件
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('错误已确认')}
        />
    );
}

6. 事件处理

6.1 基本事件处理

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>
    );
}

6.2 事件参数传递

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>
    );
}

📝 关键概念总结