个人技术分享

代码场景

ParentComponent.tsx

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const [childData, setChildData] = useState<string>('');

  const handleChildData = (data: string) => { // 可以直接将set函数作为回调函数传递给子组件,而不需要额外封装一个函数
    setChildData(data);
  };

  return (
    <div>
      <h1>Parent Component</h1>
      <ChildComponent onData={handleChildData} />
      <p>Data from Child: {childData}</p>
    </div>
  );
}

export default ParentComponent;

ChildComponent.tsx

import React from 'react';

interface ChildComponentProps {
  onData: (data: string) => void;
}

const ChildComponent: React.FC<ChildComponentProps> = ({ onData }) => {
  const sendDataToParent = () => { // 可以直接调用onData函数,不用再封装一次
    onData('Data from Child');
  };

  return (
    <div>
      <h2>Child Component</h2>
      <button onClick={sendDataToParent}>Send Data to Parent</button>
    </div>
  );
};

export default ChildComponent;

在TypeScript中,React.FC<ChildComponentProps> 是用于定义 React 函数组件的一种类型注解。它有助于确保组件的属性(props)符合预期的类型,并为组件的使用提供类型安全和智能提示。

详细解释

  • React.FCReact.FunctionComponent 的简写,是一个泛型接口,用于定义函数组件。
  • ChildComponentProps 是一个接口或类型别名,用于描述组件的 props 的结构和类型

通过使用 React.FC<ChildComponentProps>,我们告诉 TypeScript 这个函数组件将接收的 props 必须符合 ChildComponentProps 接口的定义。

示例代码

定义 ChildComponentProps 接口

首先,我们定义一个接口 ChildComponentProps,描述这个组件所需要的 props 的类型:

interface ChildComponentProps {
  data: string; // props 中需要有一个字符串类型的 `data`
}
使用 React.FC<ChildComponentProps>

然后,我们定义一个函数组件 ChildComponent,并使用 React.FC<ChildComponentProps> 进行类型注解:

import React from 'react';

interface ChildComponentProps {
  data: string;
}

const ChildComponent: React.FC<ChildComponentProps> = ({ data }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};

export default ChildComponent;

主要优势

  1. 类型安全

    • 确保组件接收的 props 符合预期的类型。在编写或使用组件时,如果提供的 props 类型不正确,TypeScript 会在编译时提示错误。
  2. 自动推断和提示

    • 使用 React.FC,TypeScript 会自动推断组件的返回类型为 JSX.Element,并为 props 提供智能提示和自动补全。
  3. 默认包含 children

    • React.FC 默认包含了 children 属性,这对于需要传递子元素的组件非常方便。如果不需要 children 属性,可以显式地将其从接口中移除。

包含 children 属性

import React from 'react';

interface ChildComponentProps {
  data: string;
}

const ChildComponent: React.FC<ChildComponentProps> = ({ data, children }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
      {children}
    </div>
  );
};

export default ChildComponent;

不包含 children 属性

如果你不希望组件接受 children 属性,可以将其显式移除:

import React, { ReactNode } from 'react';

interface ChildComponentProps {
  data: string;
  children?: never; // 显式移除 `children` 属性
}

const ChildComponent: React.FC<ChildComponentProps> = ({ data }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};

export default ChildComponent;

总结

通过使用 React.FC<ChildComponentProps> 进行类型注解,你可以确保组件的 props 类型安全,并享受更好的开发体验,包括智能提示和自动补全。 这种类型注解在团队合作和大型项目中尤其重要,因为它可以显著减少由于类型错误引起的 bug。


React.FC使用场景

使用 React.FC(全称 React.FunctionComponent)是一种定义函数组件并为其添加类型注解的方式。是否使用 React.FC 是个人喜好和团队约定的结果。以下是一些常见的情况和一些额外的注意事项,帮助你决定何时使用 React.FC

常见情况

  1. 组件有 props 传递进来
    • 当你的组件有 props 需要传递时,可以使用 React.FC<Props> 来明确指定 props 的类型。
interface ChildComponentProps {
  data: string;
}

const ChildComponent: React.FC<ChildComponentProps> = ({ data }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};
  1. 使用 children
    • React.FC 默认包括 children 属性,适用于那些需要接收子元素的组件。
interface ParentComponentProps {
  title: string;
}

const ParentComponent: React.FC<ParentComponentProps> = ({ title, children }) => {
  return (
    <div>
      <h1>{title}</h1>
      {children}
    </div>
  );
};

何时不用 React.FC

  1. 不需要 children 属性
    • 如果你的组件不需要 children 属性,使用 React.FC 可能会增加不必要的属性,可以使用常规函数组件的方式。
interface ChildComponentProps {
  data: string;
}

const ChildComponent = ({ data }: ChildComponentProps) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};
  1. 避免默认 props 和 displayName 的影响
    • 使用 React.FC 时,默认 props 和 displayName 会有一些不同的处理方式。如果你需要精确控制这些特性,可以选择不使用 React.FC
interface ChildComponentProps {
  data: string;
}

const ChildComponent = ({ data }: ChildComponentProps) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};

// 如果需要指定 displayName
ChildComponent.displayName = 'ChildComponent';

其他注意事项

  1. 定义返回类型
    • React.FC 会自动推断返回类型为 JSX.Element,如果你不使用 React.FC,可以手动指定返回类型。
interface ChildComponentProps {
  data: string;
}

const ChildComponent: React.FC<ChildComponentProps> = ({ data }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};

// 或者手动指定返回类型
const ChildComponent = ({ data }: ChildComponentProps): JSX.Element => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};
  1. 泛型组件
    • 对于泛型组件,使用 React.FC 可能会增加复杂性,直接使用函数组件的方式可能更加简洁。
interface ListComponentProps<T> {
  items: T[];
}

function ListComponent<T>({ items }: ListComponentProps<T>): JSX.Element {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
}

总结

  • 使用 React.FC 是一种选择,不是强制的。它提供了一些默认行为(如 children 支持)和类型推断,但也增加了一些额外的类型。
  • 在有 props 传递进来的情况下,使用 React.FC 或手动定义 props 类型取决于个人和团队的喜好。
  • 重要的是,在项目中保持一致的代码风格,并根据项目需求选择适合的方式。

通过这些解释和示例,希望能帮助你更好地理解何时使用 React.FC,何时选择其他方式定义 React 组件。