Skip to content

组件与组件属性

组件和 Props

1.组件

组件是 React 的核心,组件可以理解为页面的组成部分,比如页面头部,页面底部,页面主体等。React 中组件分为函数组件和类组件。

1. 函数组件

函数组件是一个返回 React 元素的函数,函数组件的名称必须以大写字母开头。

jsx
function MyComponent() {
  return <h1>Hello, world!</h1>;
}

2. 类组件

类组件是一个继承自 React.Component 的类,类组件的名称必须以大写字母开头。

jsx
class MyComponent extends React.Component {
  render() {
    return <h1>Hello, world!</h1>;
  }
}

3. 组件插槽

组件插槽(Slots)是 React 提供的一种用于组件内容传递的方式。组件插槽可以用于传递任意内容,包括文本、HTML、组件等。

jsx
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,而不是让整个应用崩溃。

jsx
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 提供的一种用于组件复用的机制。高阶组件是一个函数,接收一个组件作为参数,返回一个新的组件。高阶组件可以用于复用组件的逻辑,也可以用于增强组件的功能。

jsx
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")
);

带参数高阶组件

jsx
function withExtraProps(extraProps) {
  return function (WrappedComponent) {
    return function (props) {
      return <WrappedComponent {...props} {...extraProps} />;
    };
  };
}

const MyComponentWithExtraProps = withExtraProps({ extraProp: "extra" })(
  MyComponent
);

2.Props 属性

Props 是组件的属性,用于组件之间的数据传递。Props 是,不能在组件内部修改。Props 可以通过组件的属性传递给子组件。

jsx
// 函数组件
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 核心中分离出来,成为一个独立的包。你需要单独安装它:

bash
npm install prop-types

或者使用 Yarn:

bash
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,则会抛出警告。
jsx
MyComponent.propTypes = {
  name: PropTypes.string.isRequired,
};
  • 默认值:你可以通过静态属性 defaultProps 来设置默认的 prop 值。
jsx
MyComponent.defaultProps = {
  name: "Guest",
};

示例

以下是一个完整的示例,展示了如何在一个函数式组件中使用 PropTypes

jsx
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 属性将其绑定到组件上。

jsx
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 对象。

jsx
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 对象。

jsx
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 实现。

jsx
// 组件定义变更成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 组件。

Released under the MIT License.