簡體   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