15

I've seen two ways of declaring a SFC in React with Typescript, which are these two:

import * as React from 'react'

interface Props {
  message: string
}

const Component = (props: Props) => {
  const { message } = props
  return (
    <div>{message}</div>
  )
}

export default Component

and:

import * as React from 'react'

interface Props {
  message: string
}

const Component: React.StatelessComponent<Props> = props => {
  const { message } = props
  return (
    <div>{message}</div>
  )
}

export default Component

From this question I see that with the second way you can omit children from your interface if you are using it in your component.

Are there any more differences? Which one is the preferred one and why?

César Alberca
  • 2,321
  • 2
  • 20
  • 32

5 Answers5

19

Looks like React.SFC and React.StatelessComponent are deprecated.

Use React.FunctionComponent instead:

import * as React from 'react'

interface IProps {
  text: string
}

export const MyComponent: React.FunctionComponent<IProps> = ({ text }: IProps): JSX.Element =>
<div>{text}</div>

Technically the name doesn't imply the same thing though, as Dan Abramov summed up nicely

EDIT: Note it's often aliased as React.FC<> now.

Will Squire
  • 6,127
  • 7
  • 45
  • 57
3

UPDATE: read the final part for React Hooks update

The preferred one is React.SFC (Before React 16.7):

import * as React from 'react'

interface Props {
  message: string
}

const MyComponent: React.SFC<Props> = props => {
  const { message } = props
  return (
    <div>{message}</div>
  )
}

export default MyComponent

Why?

SFC stands for Stateless Functional Component.

About your 1st examle, given it was done "manually" it has some problems. For example, it cannot point to props.children, because it wasn't defined in your interface. You don't have this problem with React.SFC.

(Note that Stateless Functional Component, Functional Component and Stateless Component seem to mean the same but actually are 3 different things (Functional Components vs. Stateless Functional Components vs. Stateless Components)

Given you're looking for a Stateless Functional Component, React.SFC is exactly the way to go. Other options may not be functional or may not be stateles, or may not fulfill a correct Component interface (like your manual example).

EDIT: Update since React Hooks arrived:

Since React hooks arrived, function components can also have internal state, so the disctintion is smaller now. The preferred way for function components (state or stateless) now is React.FunctionComponent

const MyComponent: React.FunctionComponent<Props> = props => {
  // ... Same as above
}

Cheers, from La Paz, Bolivia.

Edgar Villegas Alvarado
  • 18,204
  • 2
  • 42
  • 61
2

The definition for React.StatelessComponent<T> is:

interface StatelessComponent<P> {
    (props: P & { children?: ReactNode }, context?: any): ReactElement<any>;
    propTypes?: ValidationMap<P>;
    contextTypes?: ValidationMap<any>;
    defaultProps?: Partial<P>;
    displayName?: string;
}

In your for snippet Component is inferred by the compiler to be:

(props: Props): ReactElement<any>

(or something similar).

If you write the first one like this:

const Component = (props: Props & { children?: ReactNode }) => {
    ...
}

You are pretty much getting the same thing (as long as you don't use the properties of Component)

Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • So, it seems that if I need to access the properties of the component or it's children the more convenient way is to use StatelessComponent and if not It's up to me to decide which one feels better, right? Also, correct me if I'm wrong, if I'm using `React.StatelessComponent` I don't have to explicitly put the return type. – César Alberca Jun 05 '17 at 22:33
  • You're free to use `StatelessComponent`, it only makes a difference if you need to access the properties of it later on. The resulting js will be the same regardless of what you do, so there's no "better solution" here. And you haven't explicitly declared the return type in both cases – Nitzan Tomer Jun 06 '17 at 12:56
2

When you declare that const Component: React.StatelessComponent<Props> You basically declaring what this function gets, and what it returns:

interface StatelessComponent<P> { (props: P ... ): ReactElement<any>;

So for readability, I would actually do:

const Component = (props: Props): JSX.Element => {

Because here the developer that looks into this code don't need to know what is the interface of StatelessComponent - he can just read what goes in and what goes out.

And basically, it is all a big:

const Component: React.StatelessComponent<Props> = (props: IProps): JSX.Element =>

alodium
  • 135
  • 11
  • True, I forgot about the return type. However, wouldn't in your example be as follows: `const Component: React.StatelessComponent = props): JSX.Element =>`, as you already declare in the interface the props of the StatelessComponent? Also, is the return type necessary if using `React.StatelessComponent`? – César Alberca Jun 05 '17 at 22:29
  • I don't get the `const Component: React.StatelessComponent = props): JSX.Element =>` question, sorry. As for the second question - it is not necessary but it might be helpful for the next developer to know what goes out, without the need to go into `React.StatelessComponent` declaration and check it. (well, in these global `React` functions it is already known, but, best practices ect...). – alodium Jun 06 '17 at 06:53
  • You are redeclaring twice the props of the component. Once here `React.StatelessComponent` and another time here: `(props: IProps)`. Isn't declared the return type in `React.StatelessComponent`? You can see it [here](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L219) – César Alberca Jun 06 '17 at 12:51
0

At the time of this writing, the trend for writing Functional React Components are:

  • Do not use React.StatelessComponent, React.SFC (Both are deprecated)
  • Omit React.FunctionComponent and React.FC (For reasons outlined below)

So the recommended style could look like:

import * as React from 'react'

interface Props {
  message: string
}

const Component = ({message}:Props) => {
  return (
    <div>{message}</div>
  )
}

export default Component

The reasoning for omitting React.FC and React.FunctionComponent can be traced to the removal from the CRA Typescript Template.

Additional thoughts can be found on Kent C Dodd's blog

In summary, the reason for removal of React.FC (and React.FunctionComponent) is the usage provides little benefit and introduces possible problems. To quote Mr. Dodds:

[Omitting the usage] doesn't have any of the shortcomings of React.FC and it's no more complicated than typing the arguments to a regular function.

A very short summary of issues using React.FC

  1. Components accepts a children prop even if you don't use it
  2. Generics are not supported
  3. Makes "component as namespace pattern" more awkward.
  4. Default Props do not work correctly
  5. It's as long, or longer than the alternative
Edgar
  • 1,174
  • 8
  • 9