Skip to content

React 组件基础

概述

组件是 React 应用的基本构建块。每个 React 应用都是由组件组成的组件树。本章将学习如何创建和使用 React 组件,包括函数组件、类组件以及组件的组合。

🧩 什么是组件

组件的基本概念

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

// 使用组件
function App() {
    return (
        <div>
            <Welcome />
            <Welcome />
            <Welcome />
        </div>
    );
}

组件的特点

  • 可复用:一次定义,多处使用
  • 独立性:每个组件管理自己的状态
  • 组合性:小组件组合成大组件
  • 声明式:描述 UI 应该是什么样子

📝 函数组件

基础函数组件

jsx
// 无参数组件
function Header() {
    return (
        <header>
            <h1>我的网站</h1>
            <nav>
                <a href="#home">首页</a>
                <a href="#about">关于</a>
                <a href="#contact">联系</a>
            </nav>
        </header>
    );
}

// 带参数的组件
function Greeting({ name, time = "上午" }) {
    return (
        <div>
            <h2>{time}好,{name}!</h2>
            <p>欢迎来到我们的网站</p>
        </div>
    );
}

// 使用组件
function App() {
    return (
        <div>
            <Header />
            <Greeting name="张三" time="下午" />
            <Greeting name="李四" />
        </div>
    );
}

箭头函数组件

jsx
// 箭头函数写法
const Button = ({ children, onClick, type = "button" }) => {
    return (
        <button type={type} onClick={onClick}>
            {children}
        </button>
    );
};

const Card = ({ title, content, imageUrl }) => (
    <div className="card">
        {imageUrl && <img src={imageUrl} alt={title} />}
        <h3>{title}</h3>
        <p>{content}</p>
    </div>
);

// 组件组合
const ProductCard = ({ product }) => (
    <Card
        title={product.name}
        content={product.description}
        imageUrl={product.image}
    />
);

🏗️ 类组件

基础类组件

jsx
import React, { Component } from 'react';

class Counter extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }
    
    increment = () => {
        this.setState({ count: this.state.count + 1 });
    };
    
    render() {
        return (
            <div>
                <h2>计数器: {this.state.count}</h2>
                <button onClick={this.increment}>
                    增加
                </button>
            </div>
        );
    }
}

// 带生命周期的类组件
class Timer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            seconds: 0
        };
    }
    
    componentDidMount() {
        this.interval = setInterval(() => {
            this.setState({ seconds: this.state.seconds + 1 });
        }, 1000);
    }
    
    componentWillUnmount() {
        clearInterval(this.interval);
    }
    
    render() {
        return (
            <div>
                <h3>已运行: {this.state.seconds} 秒</h3>
            </div>
        );
    }
}

🔧 Props 和 Children

Props 传递

jsx
function UserProfile({ user, showEmail = false, onEdit }) {
    return (
        <div className="user-profile">
            <h2>{user.name}</h2>
            <p>年龄: {user.age}</p>
            {showEmail && <p>邮箱: {user.email}</p>}
            <button onClick={() => onEdit(user.id)}>
                编辑
            </button>
        </div>
    );
}

// 使用 Props
function App() {
    const user = {
        id: 1,
        name: "张三",
        age: 25,
        email: "zhangsan@example.com"
    };
    
    const handleEdit = (userId) => {
        console.log(`编辑用户: ${userId}`);
    };
    
    return (
        <UserProfile
            user={user}
            showEmail={true}
            onEdit={handleEdit}
        />
    );
}

Children 属性

jsx
function Modal({ isOpen, onClose, children }) {
    if (!isOpen) return null;
    
    return (
        <div className="modal-overlay">
            <div className="modal">
                <button className="modal-close" onClick={onClose}>
                    ×
                </button>
                {children}
            </div>
        </div>
    );
}

function ConfirmDialog({ isOpen, onClose, onConfirm }) {
    return (
        <Modal isOpen={isOpen} onClose={onClose}>
            <h3>确认操作</h3>
            <p>您确定要执行此操作吗?</p>
            <div className="modal-actions">
                <button onClick={onConfirm}>确认</button>
                <button onClick={onClose}>取消</button>
            </div>
        </Modal>
    );
}

🎯 组件组合模式

容器组件和展示组件

jsx
// 展示组件(只负责 UI)
function TodoItem({ todo, onToggle, onDelete }) {
    return (
        <div className={`todo-item ${todo.completed ? 'completed' : ''}`}>
            <input
                type="checkbox"
                checked={todo.completed}
                onChange={() => onToggle(todo.id)}
            />
            <span>{todo.text}</span>
            <button onClick={() => onDelete(todo.id)}>删除</button>
        </div>
    );
}

// 容器组件(管理状态和逻辑)
function TodoList() {
    const [todos, setTodos] = useState([
        { id: 1, text: '学习 React', completed: false },
        { id: 2, text: '写项目文档', completed: true }
    ]);
    
    const toggleTodo = (id) => {
        setTodos(todos.map(todo =>
            todo.id === id ? { ...todo, completed: !todo.completed } : todo
        ));
    };
    
    const deleteTodo = (id) => {
        setTodos(todos.filter(todo => todo.id !== id));
    };
    
    return (
        <div className="todo-list">
            {todos.map(todo => (
                <TodoItem
                    key={todo.id}
                    todo={todo}
                    onToggle={toggleTodo}
                    onDelete={deleteTodo}
                />
            ))}
        </div>
    );
}

高阶组件模式

jsx
// 加载状态高阶组件
function withLoading(WrappedComponent) {
    return function WithLoadingComponent({ isLoading, ...props }) {
        if (isLoading) {
            return <div className="loading">加载中...</div>;
        }
        return <WrappedComponent {...props} />;
    };
}

// 使用高阶组件
const UserListWithLoading = withLoading(function UserList({ users }) {
    return (
        <ul>
            {users.map(user => (
                <li key={user.id}>{user.name}</li>
            ))}
        </ul>
    );
});

function App() {
    const [users, setUsers] = useState([]);
    const [isLoading, setIsLoading] = useState(true);
    
    useEffect(() => {
        setTimeout(() => {
            setUsers([
                { id: 1, name: '张三' },
                { id: 2, name: '李四' }
            ]);
            setIsLoading(false);
        }, 2000);
    }, []);
    
    return (
        <UserListWithLoading
            users={users}
            isLoading={isLoading}
        />
    );
}

🎨 组件样式

CSS 模块化

jsx
// Button.module.css
/*
.button {
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

.primary {
    background-color: #007bff;
    color: white;
}

.secondary {
    background-color: #6c757d;
    color: white;
}
*/

import styles from './Button.module.css';

function Button({ variant = 'primary', children, ...props }) {
    const buttonClass = `${styles.button} ${styles[variant]}`;
    
    return (
        <button className={buttonClass} {...props}>
            {children}
        </button>
    );
}

Styled Components

jsx
import styled from 'styled-components';

const StyledButton = styled.button`
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    background-color: ${props => 
        props.variant === 'primary' ? '#007bff' : '#6c757d'
    };
    color: white;
    
    &:hover {
        opacity: 0.8;
    }
`;

function Button({ variant, children, ...props }) {
    return (
        <StyledButton variant={variant} {...props}>
            {children}
        </StyledButton>
    );
}

📊 组件性能优化

React.memo

jsx
import { memo } from 'react';

const ExpensiveComponent = memo(function ExpensiveComponent({ data, filter }) {
    console.log('ExpensiveComponent 渲染');
    
    const filteredData = data.filter(item => 
        item.name.toLowerCase().includes(filter.toLowerCase())
    );
    
    return (
        <ul>
            {filteredData.map(item => (
                <li key={item.id}>{item.name}</li>
            ))}
        </ul>
    );
});

// 自定义比较函数
const CustomMemoComponent = memo(function Component({ user, settings }) {
    return (
        <div>
            <h2>{user.name}</h2>
            <p>主题: {settings.theme}</p>
        </div>
    );
}, (prevProps, nextProps) => {
    return prevProps.user.id === nextProps.user.id &&
           prevProps.settings.theme === nextProps.settings.theme;
});

📝 本章小结

组件是 React 的核心概念,通过本章学习,你应该掌握了:

关键要点

  • ✅ 函数组件和类组件的创建方式
  • ✅ Props 的传递和使用
  • ✅ Children 属性的应用
  • ✅ 组件组合和复用模式
  • ✅ 组件样式管理
  • ✅ 基础性能优化技巧

最佳实践

  1. 优先使用函数组件:更简洁,性能更好
  2. 保持组件单一职责:每个组件只做一件事
  3. 合理使用 Props:保持接口简洁明了
  4. 组件命名要清晰:使用 PascalCase 命名
  5. 适当使用 memo:避免不必要的重新渲染

继续学习下一章 - React 属性 Props

本站内容仅供学习和研究使用。