Как использовать дочерние элементы с функциональным компонентом React без сохранения состояния в TypeScript?

88

Используя TypeScript с React, нам больше не нужно расширяться, React.Propsчтобы компилятор знал, что все свойства компонентов React могут иметь дочерние элементы:

interface MyProps { }

class MyComponent extends React.Component<MyProps, {}> {
  public render(): JSX.Element {
    return <div>{this.props.children}</div>;
  }
}

Однако, похоже, это не относится к функциональным компонентам без состояния:

const MyStatelessComponent = (props: MyProps) => {
  return (
    <div>{props.children}</div>
  );
};

Выдает ошибку компиляции:

Ошибка: (102, 17) TS2339: Свойство «children» не существует для типа «MyProps».

Я предполагаю, что это потому, что компилятор действительно не может узнать, что в childrenаргументе props будет указана ванильная функция .

Итак, вопрос в том, как мы должны использовать дочерние элементы в функциональном компоненте без сохранения состояния в TypeScript?

Я мог бы вернуться к старому способу MyProps extends React.Props, но Propsинтерфейс помечен как устаревший , а компоненты без сохранения состояния не имеют и не поддерживают a, Props.refкак я понимаю.

Итак, я мог определить childrenопору вручную:

interface MyProps {
  children?: React.ReactNode;
}

Во-первых: ReactNodeправильный тип?

Во-вторых: я должен написать дочерние элементы как optional ( ?), иначе потребители подумают, что childrenэто должен быть атрибут компонента ( <MyStatelessComponent children={} />), и вызовут ошибку, если не указано значение.

Кажется, я что-то упускаю. Может ли кто-нибудь прояснить, является ли мой последний пример способом использования функциональных компонентов без сохранения состояния с дочерними элементами в React?

Аарон Билл
источник

Ответы:

89

Обновление React 16.8: Начиная с React 16.8, имена React.SFCи React.StatelessComponentустарели. Фактически, они стали псевдонимами React.FunctionComponentтипа или React.FCдля краткости.

Вы бы использовали их точно так же:

const MyStatelessComponent : React.FunctionComponent<MyProps> = props =>
    <div>
        <p>{props.propInMyProps}</p>
        <p>{props.children}</p>
    </div>

До React 16.8 (старше):

На данный момент вы можете использовать этот React.StatelessComponent<>тип как:

const MyStatelessComponent : React.StatelessComponent<{}> = props =>
    <div>{props.children}</div>

Я добавил, что установил тип возвращаемого значения для компонента React.StatelessComponent.

Для компонента с вашими собственными реквизитами (например, MyPropsинтерфейса):

const MyStatelessComponent : React.StatelessComponent<MyProps> = props =>
    <div>
        <p>{props.propInMyProps}</p>
        <p>{props.children}</p>
    </div>

Теперь у propsнего есть childrenсвойства, а также свойства MyPropsинтерфейса.

Я проверил это в машинописной версии 2.0.7

Кроме того, для краткости можно использовать React.SFCвместо React.StatelessComponent.

Леоне
источник
Благодаря! Кажется , я на старой версии типизации , которая не поддерживает это ... Я думаю , это время , чтобы стиснуть зубы и использовать TS 2.0 с@types
Aaron Beall
3
React.StatelessComponent/ React.SFCустарели. React.FunctionComponentВместо этого рекомендуется обратиться к .
Александр Качкаев
Обратите внимание, что этот метод не работает, если у вас есть общий компонент
FunkeyFlo
94

Вы можете использовать React.PropsWithChildren<P>шрифт для реквизита:

interface MyProps { }

function MyComponent(props: React.PropsWithChildren<MyProps>) {
  return <div>{props.children}</div>;
}
байтун
источник
0

Вы можете использовать

interface YourProps { }
const yourComponent: React.SFC<YourProps> = props => {}
Цзюнь Инь
источник
React.SFCустарел
Arjan
0

Более простой ответ: используйте ReactNode:

interface MyProps {
  children?: React.ReactNode
}

Если не childrenявляется обязательным или нет (т.е. имеющих ?или нет) зависит от используемого компонента. Это ?самый лаконичный способ выразить это, так что в этом нет ничего плохого.

По истории: это не обязательно был правильный ответ, когда изначально его спросили: тип ReactNodeбыл добавлен в (почти) его текущей форме в марте 2017 года только с помощью этого запроса на перенос, но почти каждый, кто читает это сегодня, должен быть на достаточно современной версии React .

Наконец, о передаче в childrenкачестве «атрибута» (который, на жаргоне React, будет передавать его как «свойство», а не атрибут): это возможно, но в большинстве случаев лучше читается при передаче дочерних элементов JSX:

<MyComponent>
  <p>This is part of the children.</p>
</MyComponent>

читает легче, чем

<MyComponent children={<p>This is part of the children.</p>} />
chris6953
источник
0

Вы можете просто добавить дочерних элементов к компоненту, и если он подключен к контейнеру, это все, что вам нужно.

const MyComponent = ({ 
   children  
}) => {
  return <div>{children}</div>

}
Н.С. Нико
источник
Зачем добавлять еще один ответ на такой старый вопрос?
Майк Шиндел
И это был вопрос TypeScript.
Жолт Месарош