函数组件是定义 React 组件最简单的方式。它是一个接收 props 对象并返回 React 元素的 JavaScript 函数。
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
特点:
使用箭头函数:
const Welcome = (props) => { return <h1>Hello, {props.name}</h1>; }; // 简写形式(隐式返回) const Welcome = (props) => <h1>Hello, {props.name}</h1>; // 解构 props const Welcome = ({ name }) => <h1>Hello, {name}</h1>;
类组件使用 ES6 的 class 语法定义,继承自 React.Component。
import React from 'react'; class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
特点:
组件可以相互组合,形成组件树。
function Welcome(props) { return <h1>Hello, {props.name}</h1>; } function App() { return ( <div> <Welcome name="张三" /> <Welcome name="李四" /> <Welcome name="王五" /> </div> ); }
提取组件:
当 UI 的一部分被多次使用,或者自身足够复杂时,可以将其提取为独立的组件。
// 原始代码 function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } // 提取 Avatar 组件 function Avatar(props) { return ( <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> ); } // 提取 UserInfo 组件 function UserInfo(props) { return ( <div className="UserInfo"> <Avatar user={props.user} /> <div className="UserInfo-name"> {props.user.name} </div> </div> ); } // 重构后的 Comment 组件 function Comment(props) { return ( <div className="Comment"> <UserInfo user={props.author} /> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
Props(properties 的缩写)是组件之间传递数据的方式。
传递 props:
function App() { return <User name="张三" age={25} isAdmin={true} />; }
接收 props:
function User(props) { return ( <div> <p>姓名:{props.name}</p> <p>年龄:{props.age}</p> <p>{props.isAdmin ? '管理员' : '普通用户'}</p> </div> ); } // 使用解构 function User({ name, age, isAdmin }) { return ( <div> <p>姓名:{name}</p> <p>年龄:{age}</p> <p>{isAdmin ? '管理员' : '普通用户'}</p> </div> ); }
Props 的只读性:
组件不能修改自己的 props。props 对于组件来说是只读的。
// 错误!props 是只读的 function Welcome(props) { props.name = 'Hello'; // 错误! return <h1>{props.name}</h1>; }
为 props 设置默认值:
函数组件:
function Button({ text = '点击', type = 'button' }) { return <button type={type}>{text}</button>; } // 或者 function Button(props) { const { text = '点击', type = 'button' } = props; return <button type={type}>{text}</button>; }
类组件:
class Button extends React.Component { static defaultProps = { text: '点击', type: 'button' }; render() { return <button type={this.props.type}>{this.props.text}</button>; } } // 或者在组件外部 Button.defaultProps = { text: '点击', type: 'button' };
PropTypes 用于运行时类型检查。
安装:
npm install prop-types
使用:
import PropTypes from 'prop-types'; function User({ name, age, email }) { return ( <div> <p>{name}</p> <p>{age}</p> <p>{email}</p> </div> ); } User.propTypes = { name: PropTypes.string.isRequired, age: PropTypes.number, email: PropTypes.string, isAdmin: PropTypes.bool, hobbies: PropTypes.array, address: PropTypes.object, onClick: PropTypes.func, element: PropTypes.element, nodes: PropTypes.node, user: PropTypes.instanceOf(User), shape: PropTypes.shape({ color: PropTypes.string, fontSize: PropTypes.number }), oneOf: PropTypes.oneOf(['News', 'Photos']), oneOfType: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]), arrayOf: PropTypes.arrayOf(PropTypes.number), objectOf: PropTypes.objectOf(PropTypes.number), any: PropTypes.any }; User.defaultProps = { age: 18 };
TypeScript 替代方案:
如果使用 TypeScript,可以使用接口定义 props 类型,获得编译时类型检查。
children 是一个特殊的 prop,用于在组件标签之间传递内容。
function Card({ title, children }) { return ( <div className="card"> <div className="card-header">{title}</div> <div className="card-body">{children}</div> </div> ); } // 使用 function App() { return ( <Card title="欢迎使用"> <p>这是卡片的内容</p> <button>了解更多</button> </Card> ); }
children 的类型:
render props 是一种在 React 组件之间使用一个值为函数的 prop 共享代码的技术。
class MouseTracker extends React.Component { state = { x: 0, y: 0 }; handleMouseMove = (event) => { this.setState({ x: event.clientX, y: event.clientY }); }; render() { return ( <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}> {this.props.render(this.state)} </div> ); } } // 使用 function App() { return ( <MouseTracker render={({ x, y }) => ( <p>鼠标位置:({x}, {y})</p> )} /> ); }
高阶组件是一个函数,接收一个组件并返回一个新的组件。
function withLogger(WrappedComponent) { return class extends React.Component { componentDidMount() { console.log('Component mounted:', WrappedComponent.name); } render() { return <WrappedComponent {...this.props} />; } }; } // 使用 const EnhancedComponent = withLogger(MyComponent);
常见的 HOC 用途:
按功能组织:
src/ ├── components/ # 可复用的 UI 组件 │ ├── Button/ │ │ ├── Button.js │ │ ├── Button.css │ │ └── Button.test.js │ └── Card/ ├── features/ # 功能模块 │ ├── User/ │ │ ├── UserList.js │ │ ├── UserForm.js │ │ └── userSlice.js │ └── Product/ ├── hooks/ # 自定义 Hooks ├── utils/ # 工具函数 ├── api/ # API 调用 └── App.js
按类型组织:
src/ ├── components/ # 所有组件 ├── containers/ # 容器组件 ├── actions/ # Redux actions ├── reducers/ # Redux reducers ├── utils/ # 工具函数 └── App.js
本章介绍了组件的基础知识:
组件是 React 的核心概念,理解组件的各种用法是掌握 React 的关键。