繁体   English   中英

如何使用 TypeScript 为无状态的功能性 React 组件指定(可选)默认道具?

[英]How to specify (optional) default props with TypeScript for stateless, functional React components?

我正在尝试在 Typescript 中创建一个带有可选 props 和 defaultProps 的无状态 React 组件(用于 React Native 项目)。 这对于 vanilla JS 来说是微不足道的,但我对如何在 TypeScript 中实现它感到困惑。

使用以下代码:

import React, { Component } from 'react';
import { Text } from 'react-native';

interface TestProps {
    title?: string,
    name?: string
}

const defaultProps: TestProps = {
    title: 'Mr',
    name: 'McGee'
}

const Test = (props = defaultProps) => (
    <Text>
        {props.title} {props.name}
    </Text>
);

export default Test;

调用<Test title="Sir" name="Lancelot" />会按预期呈现“Sir Lancelot”,但<Test />应该输出“Mr McGee”时什么结果都没有。

任何帮助是极大的赞赏。

这是一个带有答案的类似问题: React with TypeScript - 在无状态函数中定义 defaultProps

import React, { Component } from 'react';
import { Text } from 'react-native';

interface TestProps {
    title?: string,
    name?: string
}

const defaultProps: TestProps = {
    title: 'Mr',
    name: 'McGee'
}

const Test: React.SFC<TestProps> = (props) => (
    <Text>
        {props.title} {props.name}
    </Text>
);

Test.defaultProps = defaultProps;

export default Test;

我发现最简单的方法是使用可选参数。 请注意, defaultProps 最终将在功能组件上弃用

示例:

interface TestProps {
    title?: string;
    name?: string;
}

const Test = ({title = 'Mr', name = 'McGee'}: TestProps) => {
    return (
        <p>
            {title} {name}
        </p>
    );
}

这是我喜欢这样做的方式:

type TestProps = { foo: Foo } & DefaultProps
type DefaultProps = Partial<typeof defaultProps>
const defaultProps = {
  title: 'Mr',
  name: 'McGee'
}

const Test = (props: Props) => {
  props = {...defaultProps, ...props}
  return (
    <Text>
      {props.title} {props.name}
    </Text>
  )
}

export default Test

将我的解决方案添加到锅中,我认为它为现有解决方案增加了额外的可读性和优雅度。

假设您有一个MyComponent组件,其中包含必需和可选的 props。 我们可以将这些必需的和可选的 props 分成两个接口,将它们组合起来作为组件的完整 prop 接口,但只使用可选的一个来设置默认的 props:

import * as React from "react";

// Required props
interface IMyComponentRequiredProps {
  title: string;
}

// Optional props
interface IMyComponentOptionalProps {
  color: string;
  fontSize: number;
}

// Combine required and optional props to build the full prop interface
interface IMyComponentProps
  extends IMyComponentRequiredProps,
    IMyComponentOptionalProps {}

// Use the optional prop interface to define the default props
const defaultProps: IMyComponentOptionalProps = {
  color: "red",
  fontSize: 40,
};

// Use the full props within the actual component
const MyComponent = (props: IMyComponentProps) => {
  const { title, color, fontSize } = props;
  return <h1 style={{ color, fontSize }}>{title}</h1>;
};

// Be sure to set the default props
MyComponent.defaultProps = defaultProps;

export default MyComponent;

我可能是错的,但是在函数上传递一个默认的 prop 值作为第二个投票的回复说可能会导致微妙的错误或过度执行 useEffects(我没有足够的代表来回复那里,所以这里有一个可重复的 codesanbox)

即使它是一个非常人为的例子,并且可能在大多数情况下只是糟糕的组件设计,我已经不止一次看到这种情况,甚至打破了整页。

2022 年更新

对于功能组件,确实有可能弃用defaultProps字段。 我不相信这会很快发生,因为已经用它编写了大量的代码,但是很可能会在控制台中显示警告。

我正在使用下面的解决方案,它提供了正确的行为和正确的 TypeScript 验证。 它适用于混合定义/未定义的属性,也适用于有/没有默认值的属性——也就是说,它涵盖了所有情况:

interface Props {
  name: string;
  surname?: string;
  age?: number;
}

const defaultProps = {
  surname: 'Doe',
};

function MyComponent(propsIn: Props) {
  const props = {...defaultProps, ...propsIn};

  return <div>{props.surname}</div>;
}

VSCode 自动完成功能在:

VSCode 自动完成

它已经使用 TypeScript 4.7 进行了测试。

对我来说,这看起来不像是打字稿问题。

免责声明:我只用打字稿试过这个。

然而,问题在于 props总是存在的(即使没有传入任何内容时作为空对象)。 不过,有两种解决方法。

不幸的是,第一个会扼杀您拥有的超级干净的无花括号语法,但让我们保留defaultProps

interface TestProps {
    title?: string;
    name?: string;
}

const defaultProps: TestProps = {
    title: 'Mr',
    name: 'McGee'
}

const Test = (passedIn: TestProps) => {
    const props = Object.assign({}, defaultProps, passedIn);
    return (
        <p>
            {props.title} {props.name}
        </p>
    );
}

如果您有大量道具,另一种选择可能会有点麻烦,但这可以让您保留原始语法,如下所示:

const Test = (props: TestProps) => (
    <Text>
        {props.title || 'Mr'} {props.name || 'McGee'}
    </Text>
);

希望这有帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM