组件基础 #

一、组件概述 #

组件是 React 的核心概念,将 UI 拆分为独立、可复用的部分,每个组件管理自己的状态和逻辑。

1.1 组件定义 #

javascript
// 组件是返回JSX的函数
function Welcome() {
  return <h1>Hello, React!</h1>;
}

1.2 组件特点 #

特点 说明
独立性 组件管理自己的状态和逻辑
可复用 组件可在不同地方重复使用
可组合 小组件组合成大组件
可测试 独立组件易于测试

二、函数组件 #

2.1 基本定义 #

javascript
// 函数声明
function Welcome() {
  return <h1>Hello, React!</h1>;
}

// 函数表达式
const Welcome = function() {
  return <h1>Hello, React!</h1>;
};

// 箭头函数
const Welcome = () => <h1>Hello, React!</h1>;

2.2 接收Props #

javascript
function Welcome({ name, age }) {
  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>Age: {age}</p>
    </div>
  );
}

// 使用
<Welcome name="Alice" age={25} />

2.3 带状态的函数组件 #

javascript
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        增加
      </button>
    </div>
  );
}

三、类组件 #

3.1 基本定义 #

javascript
import { Component } from 'react';

class Welcome extends Component {
  render() {
    return <h1>Hello, React!</h1>;
  }
}

3.2 接收Props #

javascript
class Welcome extends Component {
  render() {
    const { name, age } = this.props;
    return (
      <div>
        <h1>Hello, {name}!</h1>
        <p>Age: {age}</p>
      </div>
    );
  }
}

3.3 带状态的类组件 #

javascript
import { 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>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>增加</button>
      </div>
    );
  }
}

3.4 类组件生命周期 #

javascript
import { Component } from 'react';

class LifecycleDemo extends Component {
  constructor(props) {
    super(props);
    console.log('1. constructor');
    this.state = { count: 0 };
  }

  static getDerivedStateFromProps(props, state) {
    console.log('2. getDerivedStateFromProps');
    return null;
  }

  componentDidMount() {
    console.log('3. componentDidMount');
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log('4. shouldComponentUpdate');
    return true;
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('5. getSnapshotBeforeUpdate');
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('6. componentDidUpdate');
  }

  componentWillUnmount() {
    console.log('7. componentWillUnmount');
  }

  render() {
    console.log('render');
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          增加
        </button>
      </div>
    );
  }
}

四、函数组件 vs 类组件 #

4.1 对比表 #

特性 函数组件 类组件
语法 简洁 复杂
状态管理 Hooks this.state
生命周期 useEffect 生命周期方法
this 需要绑定
性能 略优 略差
推荐程度 推荐 维护模式

4.2 代码对比 #

javascript
// 函数组件
function Counter() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    console.log('组件挂载或更新');
    return () => console.log('清理');
  }, [count]);

  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}

// 类组件
class Counter extends Component {
  state = { count: 0 };

  componentDidMount() {
    console.log('组件挂载');
  }

  componentDidUpdate() {
    console.log('组件更新');
  }

  componentWillUnmount() {
    console.log('组件卸载');
  }

  render() {
    return (
      <button onClick={() => this.setState({ count: this.state.count + 1 })}>
        {this.state.count}
      </button>
    );
  }
}

五、组件组合 #

5.1 组件嵌套 #

javascript
function Header() {
  return <header>Header</header>;
}

function Main() {
  return <main>Main Content</main>;
}

function Footer() {
  return <footer>Footer</footer>;
}

function App() {
  return (
    <div>
      <Header />
      <Main />
      <Footer />
    </div>
  );
}

5.2 children属性 #

javascript
function Card({ title, children }) {
  return (
    <div className="card">
      <div className="card-header">
        <h2>{title}</h2>
      </div>
      <div className="card-body">
        {children}
      </div>
    </div>
  );
}

function App() {
  return (
    <Card title="用户信息">
      <p>Name: Alice</p>
      <p>Age: 25</p>
    </Card>
  );
}

5.3 组件作为属性 #

javascript
function Layout({ header, sidebar, content, footer }) {
  return (
    <div className="layout">
      <header>{header}</header>
      <div className="main">
        <aside>{sidebar}</aside>
        <main>{content}</main>
      </div>
      <footer>{footer}</footer>
    </div>
  );
}

function App() {
  return (
    <Layout
      header={<h1>My App</h1>}
      sidebar={<nav>Navigation</nav>}
      content={<article>Content</article>}
      footer={<p>© 2024</p>}
    />
  );
}

六、组件拆分原则 #

6.1 单一职责原则 #

每个组件只做一件事:

javascript
// ❌ 违反单一职责
function UserCard({ user }) {
  return (
    <div>
      <img src={user.avatar} />
      <h2>{user.name}</h2>
      <p>{user.email}</p>
      <UserStats stats={user.stats} />
      <UserPosts posts={user.posts} />
    </div>
  );
}

// ✅ 遵循单一职责
function UserCard({ user }) {
  return (
    <div>
      <UserAvatar user={user} />
      <UserInfo user={user} />
      <UserStats stats={user.stats} />
      <UserPosts posts={user.posts} />
    </div>
  );
}

6.2 组件粒度 #

text
组件层次
├── 页面组件(Page)
│   └── 整个页面
├── 布局组件(Layout)
│   └── 页面结构
├── 业务组件(Business)
│   └── 业务功能模块
└── 基础组件(UI)
    └── 可复用UI组件

6.3 拆分时机 #

应该拆分的情况

  • 组件代码超过 200 行
  • 组件有多个职责
  • 部分逻辑可复用
  • 组件状态过于复杂

不应该拆分的情况

  • 组件逻辑简单
  • 拆分后增加复杂度
  • 没有复用需求

七、组件命名规范 #

7.1 命名规则 #

javascript
// ✅ 好的命名:PascalCase
function UserProfile() {}
function ShoppingCart() {}
function NavigationBar() {}

// ❌ 不好的命名
function userProfile() {}
function shopping_cart() {}

7.2 文件命名 #

text
components/
├── UserProfile/
│   ├── index.jsx
│   ├── UserProfile.jsx
│   └── UserProfile.css
├── ShoppingCart/
│   └── index.jsx
└── NavBar/
    └── index.jsx

7.3 组件名称要有意义 #

javascript
// ❌ 不好的命名
function Component1() {}
function Wrapper() {}
function Container() {}

// ✅ 好的命名
function UserAvatar() {}
function ModalDialog() {}
function FormContainer() {}

八、组件最佳实践 #

8.1 保持组件纯净 #

javascript
// ❌ 副作用
let count = 0;
function Counter() {
  count++;
  return <div>{count}</div>;
}

// ✅ 纯函数
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      {count}
      <button onClick={() => setCount(c => c + 1)}>+</button>
    </div>
  );
}

8.2 Props验证 #

javascript
// 使用PropTypes(开发模式)
import PropTypes from 'prop-types';

function UserCard({ name, age, email }) {
  return (
    <div>
      <h2>{name}</h2>
      <p>Age: {age}</p>
      <p>Email: {email}</p>
    </div>
  );
}

UserCard.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number,
  email: PropTypes.string
};

UserCard.defaultProps = {
  age: 0,
  email: ''
};

8.3 避免prop drilling #

javascript
// ❌ prop drilling
function App() {
  const user = { name: 'Alice' };
  return <Layout user={user} />;
}

function Layout({ user }) {
  return <Sidebar user={user} />;
}

function Sidebar({ user }) {
  return <UserCard user={user} />;
}

// ✅ 使用Context或组合
function App() {
  const user = { name: 'Alice' };
  return (
    <Layout>
      <Sidebar>
        <UserCard user={user} />
      </Sidebar>
    </Layout>
  );
}

8.4 组件文档化 #

javascript
/**
 * UserCard 组件 - 显示用户信息卡片
 * 
 * @param {Object} props
 * @param {string} props.name - 用户名
 * @param {number} props.age - 年龄
 * @param {string} props.email - 邮箱地址
 * 
 * @example
 * <UserCard name="Alice" age={25} email="alice@example.com" />
 */
function UserCard({ name, age, email }) {
  return (
    <div className="user-card">
      <h2>{name}</h2>
      <p>Age: {age}</p>
      <p>Email: {email}</p>
    </div>
  );
}

九、总结 #

要点 说明
优先函数组件 函数组件更简洁,推荐使用
单一职责 每个组件只做一件事
合理拆分 根据职责和复用需求拆分
规范命名 使用 PascalCase 命名
保持纯净 避免副作用

组件化开发核心:

  • 组件是 React 应用的构建块
  • 函数组件是现代 React 的首选
  • 组件组合优于继承
  • 保持组件简单、专注、可复用
最后更新:2026-03-26