【问题标题】:How to specify (optional) default props with TypeScript for stateless, functional React components?如何使用 TypeScript 为无状态的功能性 React 组件指定(可选)默认道具?
【发布时间】:2017-03-05 16:41:43
【问题描述】:

我正在尝试在 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;

调用&lt;Test title="Sir" name="Lancelot" /&gt; 会按预期呈现“Sir Lancelot”,但&lt;Test /&gt; 在应该输出时什么也没有 “麦基先生”。

非常感谢任何帮助。

【问题讨论】:

  • Test.defaultProps = defaultProps 呢?
  • 附注:尝试使用Partial&lt;Props&gt; 指定道具子集

标签: javascript reactjs typescript react-native


【解决方案1】:

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

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

但是,问题在于 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>
);

希望这会有所帮助!

【讨论】:

  • 你不必使用传入的 props 和默认值来执行 Object.assign - 这就是 React 自动执行的操作。
  • 您的解决方案可能会奏效,但它是错误的。您应该使用无状态组件函数的defaultProps 静态属性来定义默认属性值。
  • @TomaszKajtoch 根据this answer defaultProps 在功能组件中被贬值,你能建议一种不使用defaultProps 的方法吗?
【解决方案2】:

这是一个类似的问题和答案:React with TypeScript - define defaultProps in stateless function

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;

【讨论】:

  • 这是正确答案。最近,SFC 被弃用,取而代之的是 FunctionComponent: const Test: React.FunctionComponent = ...
  • 你也可以在 typescript 中使用 React.FC,而不是 React.FunctionComponent
  • 如果属性类似于names?: string[] 怎么办?即使我给出这样的默认值,从打字稿的角度来看它仍然是可选的,所以我必须写props.names?.join(',')而不是props.names.join(',')
  • 只有在所有道具都是可选的情况下才有效
【解决方案3】:

我发现最简单的方法是使用可选参数。请注意,defaultProps 最终将是 deprecated on functional components

例子:

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

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

【讨论】:

  • 是的!函数式组件的部分优点在于您可以使用所有标准的 javascript 函数。
  • 如果默认值是数组[]或对象{}怎么办?它们不能作为钩子的依赖,因为它们每次都是新创建的,并且会触发钩子运行
  • 据我所知,无论您输入哪个默认值,代码的功能都应该相同。如果您可以链接到重现您正在谈论的问题的代码,那将是很棒的 [] 或{}
  • 只有在所有道具都是可选的情况下才有效
【解决方案4】:

我喜欢这样做:

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

【讨论】:

  • 看起来不错,你能解释一下第一行吗?
  • 当道具是必需道具和非必需道具的混合时,这是唯一正确的答案。所有其他解决方案都涉及只有可选道具的组件。
【解决方案5】:

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

假设您有一个组件MyComponent,其中混合了必需和可选道具。我们可以将这些必需的和可选的 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;

【讨论】:

  • 在另一个文件中调用 MyComponent 并且未在其中声明颜色和字体大小时仍然出现错误“属性缺少类型”。当 IMyComponentOptionalProps 上的所有道具都是可选的时,此错误将消失,例如 color?: red, fontSize?: 40
  • 这是一个包含这个确切组件的代码框:codesandbox.io/s/delicate-pine-e3u2g 这个模式有效。
  • 嗯,好的,谢谢,现在我知道我的问题了,使用 styled-component 时默认道具效果不佳。导致所需所有道具(包括声明的道具)出错的 MyComponent 更改类型。
  • 链接更新:codesandbox.io/s/…
【解决方案6】:

我可能错了,但是在第二个投票回复中传递函数的默认 prop 值可能会导致细微的错误或过度执行 useEffects(我没有足够的代表在那里回复,所以 here's a可重现的codesanbox)

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

【讨论】:

    猜你喜欢
    • 2019-12-25
    • 2020-12-21
    • 2021-10-22
    • 2020-05-15
    • 2020-03-14
    • 2018-05-26
    • 2016-04-17
    • 1970-01-01
    • 2019-12-27
    相关资源
    最近更新 更多