组件与组件属性
组件和 Props
1.组件
组件是 React 的核心,组件可以理解为页面的组成部分,比如页面头部,页面底部,页面主体等。React 中组件分为函数组件和类组件。
1. 函数组件
函数组件是一个返回 React 元素的函数,函数组件的名称必须以大写字母开头。
function MyComponent() {
return <h1>Hello, world!</h1>;
}2. 类组件
类组件是一个继承自 React.Component 的类,类组件的名称必须以大写字母开头。
class MyComponent extends React.Component {
render() {
return <h1>Hello, world!</h1>;
}
}3. 组件插槽
组件插槽(Slots)是 React 提供的一种用于组件内容传递的方式。组件插槽可以用于传递任意内容,包括文本、HTML、组件等。
function MyComponent() {
return (
<div>
<h1>Hello, world!</h1>
<p>This is a paragraph.</p>
{/* 组件预留空间 */}
{this.props.children}
{/* 组件插槽 */}
<slot></slot>
</div>
);
}
ReactDOM.render(
<MyComponent>
<p>This is a slot content.</p>
</MyComponent>,
document.getElementById("root")
);4. 错误边界
错误边界(Error Boundaries)是 React 提供的一种用于捕获和处理组件渲染过程中的错误的机制。错误边界可以用于捕获组件渲染过程中的错误,并显示一个备用 UI,而不是让整个应用崩溃。
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志记录到错误报告服务
console.log(error, errorInfo);
}
render() {
if (this.state.hasError) {
// 你可以自定义降级 UI 并渲染
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
// 使用时,包住需要捕获错误的组件
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>;5. 高阶组件
高阶组件(Higher-Order Components,简称 HOC)是 React 提供的一种用于组件复用的机制。高阶组件是一个函数,接收一个组件作为参数,返回一个新的组件。高阶组件可以用于复用组件的逻辑,也可以用于增强组件的功能。
function withExtraProps(WrappedComponent) {
return function (props) {
return <WrappedComponent {...props} extraProp="extra" />;
};
}
class MyComponent extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
const MyComponentWithExtraProps = withExtraProps(MyComponent);
ReactDOM.render(
<MyComponentWithExtraProps name="world" />,
document.getElementById("root")
);带参数高阶组件
function withExtraProps(extraProps) {
return function (WrappedComponent) {
return function (props) {
return <WrappedComponent {...props} {...extraProps} />;
};
};
}
const MyComponentWithExtraProps = withExtraProps({ extraProp: "extra" })(
MyComponent
);2.Props 属性
Props 是组件的属性,用于组件之间的数据传递。Props 是,不能在组件内部修改。Props 可以通过组件的属性传递给子组件。
// 函数组件
function MyComponent(props) {
return <h1>Hello, {props.name}!</h1>;
}
// 类组件
class MyComponent extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
ReactDOM.render(<MyComponent name="world" />, document.getElementById("root"));在上面的例子中,MyComponent 组件接收一个 name 属性,并将其显示在页面上。
3.PropTypes 类型检测
PropTypes 是 React 提供的一个库,用于对组件的 props 进行类型检查。这有助于确保组件接收到的数据符合预期,并且可以在开发过程中帮助捕获潜在的问题。虽然在生产环境中这些检查会被移除以优化性能,但在开发阶段它们非常有用。
安装 PropTypes
如果你使用的是 React 15.5 或更高版本,PropTypes 已经从 React 核心中分离出来,成为一个独立的包。你需要单独安装它:
npm install prop-types或者使用 Yarn:
yarn add prop-types使用 PropTypes
一旦安装了 prop-types,你就可以在组件中导入并定义 props 的预期类型。下面是一些常见的 PropTypes 类型及其用法:
基本类型检测
PropTypes.array:验证 prop 是否为数组。PropTypes.bool:验证 prop 是否为布尔值。PropTypes.func:验证 prop 是否为函数。PropTypes.number:验证 prop 是否为数字。PropTypes.object:验证 prop 是否为对象。PropTypes.string:验证 prop 是否为字符串。PropTypes.symbol:验证 prop 是否为符号(ES6 引入)。
复杂类型检测
PropTypes.node:验证 prop 是否为 React 子节点(可以是元素、字符串、数字或数组等)。PropTypes.element:验证 prop 是否为一个 React 元素。PropTypes.instanceOf(Message):验证 prop 是否为特定类的实例。PropTypes.oneOf(['News', 'Photos']):验证 prop 是否为指定值中的一个。PropTypes.oneOfType([PropTypes.string, PropTypes.number]):验证 prop 是否为多个可能类型的其中之一。PropTypes.arrayOf(PropTypes.number):验证 prop 是否为特定类型的数组。PropTypes.objectOf(PropTypes.number):验证 prop 是否为所有值都是特定类型的对象。PropTypes.shape({ color: PropTypes.string }):验证 prop 是否为具有特定结构的对象。
默认值和必需属性
.isRequired:标记某个 prop 为必需项。如果未提供该 prop,则会抛出警告。
MyComponent.propTypes = {
name: PropTypes.string.isRequired,
};- 默认值:你可以通过静态属性
defaultProps来设置默认的 prop 值。
MyComponent.defaultProps = {
name: "Guest",
};示例
以下是一个完整的示例,展示了如何在一个函数式组件中使用 PropTypes:
import React from "react";
import PropTypes from "prop-types";
function Greeting({ name, list, enthusiasmLevel = 1 }) {
return (
<div className="greeting">
Hello {name + getExclamationMarks(enthusiasmLevel)}
<ul>
{props.list.map((item) => (
<li key={item.id}>
【姓名】{item.name},【年龄】{item.age}
</li>
))}
</ul>
</div>
);
}
Greeting.propTypes = {
name: PropTypes.string.isRequired,
enthusiasmLevel: PropTypes.number,
};
Greeting.defaultProps = {
enthusiasmLevel: 1,
};
// 定义 studentList 的 PropType
// PropTypes.arrayOf(...):确保 studentList 是一个数组。
// PropTypes.shape({...}):定义对象的形状,即对象应该有的属性及其类型。
// .isRequired:标记该属性为必需项。如果未提供或不符合预期类型,则会抛出警告。
StudentList.propTypes = {
studentList: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string.isRequired,
age: PropTypes.number.isRequired,
})
).isRequired,
};
function getExclamationMarks(numChars) {
return Array(numChars + 1).join("!");
}
export default Greeting;在这个例子中,name 必须是字符串,并且是必需的;而 enthusiasmLevel 则是可选的数字,默认值为 1。
注意事项
- 仅限开发环境:
PropTypes检查只会在开发模式下执行,在生产构建中会被移除以提高性能。 - 性能影响:尽管
PropTypes对于调试非常有用,但请记住它们会对应用性能产生轻微的影响,特别是在大型应用中。
4.Refs
Refs 是 React 提供的一个用于访问 DOM 元素或者组件实例的属性。Refs 可以通过 React.createRef() 创建,然后通过 ref 属性将其绑定到组件上。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
console.log(this.myRef.current); // 输出 DOM 元素
}
render() {
return <div ref={this.myRef}>Hello, world!</div>;
}
}在上面的例子中,MyComponent 组件的 myRef 属性是一个 React.createRef() 创建的 Ref 对象,然后通过 ref 属性将其绑定到 div 元素上。在 componentDidMount 生命周期方法中,可以通过 this.myRef.current 访问 div 元素。
1. Refs 与类组件:
在类组件中,可以通过 this.refs 访问 Ref 对象。
class MyComponent extends React.Component {
render() {
return <div ref="myRef">Hello, world!</div>;
}
}
// 在类组件中,可以通过 this.refs 访问 Ref 对象
console.log(this.refs.myRef);2. Refs 与函数组件:
在函数组件中,可以通过 useRef Hook 访问 Ref 对象。
import React, { useRef } from "react";
function MyComponent() {
const myRef = useRef();
console.log(myRef.current); // 输出 DOM 元素
return <div ref={myRef}>Hello, world!</div>;
}3. Refs 传递
Refs 不能通过 props 传递给子组件。如果需要将 Ref 传递给子组件,可以通过 React.forwardRef 实现。
// 组件定义变更成React.forwardRef形式,而不是extends React.Components
const MyComponent = React.forwardRef((props, ref) => {
return <div ref={ref}>Hello, world!</div>;
});
// 在父组件中,可以通过 ref 属性将 Ref 传递给子组件
const myRef = React.createRef();
<MyComponent ref={myRef} />;在上面的例子中,MyComponent 组件通过 React.forwardRef 将 Ref 传递给了 div 元素。在父组件中,可以通过 ref 属性将 Ref 传递给 MyComponent 组件。