【question】defaultProps 使用问题

348 阅读4分钟

warning: WithTracking(App): Support for defaultProps will be removed from function components in a future major please,Use javascript default parameters instead.

这个警告背后确实涉及 TypeScript 类型推断的局限性,同时也是 React 官方推动代码规范化和未来兼容性的结果。这个警告是指在React的未来版本中,function components(函数组件)将不再支持defaultProps,建议你改用JavaScript的默认参数语法来替代defaultProps。以下是详细解释:

1. defaultProps 在 TS 中的类型推断问题

当你在函数组件中使用 defaultProps 时,TypeScript 无法自动将默认值合并到组件的 props 类型中,导致需要手动处理类型,例如:

interface Props {
  name: string;
  count?: number;
}

// ❌ 需要额外类型断言告诉 TS "count 一定有值"
const MyComponent = ({ name, count }: Props) => {
  return <div>{name} clicks: {count}</div>;
};

MyComponent.defaultProps = {
  count: 0
};

// 使用时 TS 会认为 `count` 是可选参数,但实际运行时已被默认值覆盖
<MyComponent name="test" />; // TS 不会报错(正确)
<MyComponent name="test" count={undefined} />; // TS 允许,但实际行为可能不符合预期

若改用 ES6 默认参数,TypeScript 能直接推断出正确的类型

interface Props {
  name: string;
  count?: number;
}

// ✅ 直接通过默认参数明确类型
const MyComponent = ({ name, count = 0 }: Props) => {
  return <div>{name} clicks: {count}</div>;
};

// 使用时:
<MyComponent name="test" />; // count 默认为 0(类型安全)
<MyComponent name="test" count={undefined} />; // TS 报错(符合预期)

2. React 官方推荐默认参数的核心原因

除了 TypeScript 类型问题,还有以下关键因素:

  • 代码简洁性:默认参数直接在函数签名中定义,逻辑更集中。
  • 运行时性能defaultProps 是 React 的运行时特性,而默认参数是 JavaScript 原生语法,可能被引擎优化。
  • 未来兼容性:React 计划逐步弃用类组件模式,推动函数式+Hooks 的现代化写法,减少历史包袱。
  • 一致性:Hooks 组件(如 useState)天然适合默认参数,统一编码风格。

3. 如何正确迁移?

场景 1:简单默认值

直接使用 ES6 默认参数:

interface Props {
  disabled?: boolean;
}

const Button = ({ disabled = false }: Props) => {
  return <button disabled={disabled}>Click</button>;
};

场景 2:复杂默认值

若默认值依赖其他参数,可结合解构和默认值:

interface Props {
  size?: "small" | "medium" | "large";
  color?: string;
}

const Icon = ({ 
  size = "medium",
  color = size === "small" ? "#999" : "#333"
}: Props) => {
  // ...
};

场景 3:需要保留 defaultProps(如库组件)

若因特殊原因仍需使用 defaultProps,可通过 类型断言 明确类型:

interface Props {
  width?: number;
}

const Divider = ({ width }: Props) => {
  return <div style={{ width }} />;
};

Divider.defaultProps = {
  width: 100
} as Partial<Props>; // 强制类型断言

总结

  • TypeScript 类型推断:默认参数天然与 TS 类型系统协作更好,无需手动处理类型合并。
  • 代码质量:减少冗余代码,提升可读性和可维护性。
  • 未来导向:遵循 React 官方最佳实践,避免未来版本升级时的重构成本。

建议逐步将现有组件的 defaultProps 迁移到默认参数,以保持代码现代化和类型安全。

解决方法是将原先通过defaultProps设置默认值的方式,改为在函数参数中直接设置默认值。以下是两种方式的对比:

使用defaultProps的方式:

function MyComponent({ title }) {
  return <h1>{title}</h1>;
}

MyComponent.defaultProps = {
  title: "默认标题",
};

改为使用默认参数的方式:

function MyComponent({ title = "默认标题" }) {
  return <h1>{title}</h1>;
}

这样做不仅符合最新的React规范,还可以避免未来的警告和可能的兼容性问题。

思考:

React的函数组件中使用defaultProps来设置默认属性,这在类组件中很常见。然而,对于函数组件,尤其是使用TypeScript时,使用ES6的默认参数可能更直接,并且类型推断更准确。例如,当使用defaultProps时,TypeScript可能需要额外的类型声明来合并默认属性,而默认参数则可以在函数签名中直接处理,类型推断更自然。

然后,我需要考虑可能的例子。比如,一个函数组件接收一个可选属性,如果使用defaultProps,类型可能需要定义为包含可选属性,而使用默认参数时,可以直接在参数中设置默认值,TypeScript会自动推断出正确的类型,不需要额外处理。这样代码更简洁,类型更安全。

另外,React官方可能出于减少API复杂性和统一代码风格的考虑,推荐使用JavaScript原生特性(默认参数)而不是React特定的defaultProps。特别是随着Hooks的普及,函数组件的写法更倾向于使用纯JavaScript特性,而不是类组件的模式。

可能还需要提到社区的趋势,比如许多现有的代码库和教程正在迁移到默认参数,而TypeScript对默认参数的支持更为成熟,减少了类型错误的机会。此外,当使用默认参数时,组件的使用者在调用时就能看到默认值,提高了代码的可读性和可维护性。

最后,总结这些点,说明使用默认参数在TypeScript中类型推断更优,同时还有其他好处如代码简洁和未来兼容性。因此,React推荐改用默认参数代替defaultProps