Table of contents

Why using React.FC could be a bad practice?

Why using React.FC could be a bad practice?

When we use Typescript with React and we want to pass a children as prop to one of our components , we need to indicate the type. Generally we use the type React.FC, which is short for React.FunctionComponent. With this the Typescript message warning us of a children with type any will disappear.

const Component: React.FC = ({ children }) => {
    return (<div>{children}</div>)
}

In addition to allowing us to work with children, React.FC also causes an error if we try to return undefined from our component.

const Component: React.FC = ({ children }) => {
    // Type '() => undefined' can't be assigned to type 'FC<{}>'.
    return undefined
}

export default Component

As you can see, it is quite comfortable to use, but some people do not agree with its use.

React.FC, more disadvantages than advantages?

What’s the problem? Well, some developers claim that React.FC can bring more disadvantages than advantages, there is even a discussion on github (link at the end), in which it is debated whether it is convenient to remove one of the examples in the documentation that uses it.

The user who started this discussion believes that **the fact that React.FC is so popular is because its presence in the documentation positions it as the default way to handle React components with Typescript.

Here are some of the reasons why React.FC has more disadvantages than advantages.

React.FC does not warn us about unused children

React.FC is not always the most explicit way to tell typescript that a component receives children as part of its props.

Imagine that we pass a children to the component, but we don’t use it.

import Component from './Component';

function App() {
  return (
    <Component>I'm the children component</Component>
  );
}

export default App;

Our component does receive the children as a prop, but the React.FC type appeases Typescript and prevents it from returning an error, even if we are not using it.

const Component: React.FC = () => {
    return (
        <div>I'm not the children which receives the component</div>
    )
}

export default Component

Or, for an opposite case; imagine that we do not want our component to receive a children as one of its props, however, as we are using React.FC we will not get any error.

import Component from './Component';

function App() {
  return (
    <Component><div>I shouldn't be here</div></Component>
  );
}

export default App;

Subcomponent pattern in React gets more complicated

The component pattern as namespace is fairly simple to create without using React.FC, but with React.FC it can get quite complicated.

Don’t know what it is? Think of a pattern that allows you to group components within a certain parent, which functions as a namespace for our child components; similar to how the C++ namespace std would work.

<Namespace>
    <Namespace.Component />
</Namespace>

In its simplest form, omitting React.FC would look something like this:

const Namespace = (props: NamespaceProps) => {/* ... */}
Namespace.Component = (props: ComponentProps) => { /*...*/ }

But if we choose to use React.FC the code would become more complicated and the readability would decrease a bit.

const Namespace: React.FC<NamespaceProps> & { Component: React.FC<ComponentProps> } = (props) => {/* ... */ }
Namespace.Component = (props) => { /*...*/ }

What should we use instead of React.FC?

The core of the criticism is that React.FC adds the children implicitly, going against the explicit nature of typescript.

However, the discussion I am talking about is just that, a discussion, it is not written in stone, you may consider that it is better to sacrifice a bit of readability in favor of convenience or, on the contrary, you may believe that it is important to be explicit when working with typescript.

If this is the case, consider that you can always declare the children as a prop explicitly, just as you would any other prop. And in the same way, you can declare the return value of your component as a JSX type element.

interface propsWithChildren {
    children: React.ReactNode
}

const Component = ({ children }: propsWithChildren): JSX.Element => {
    return (
        <div>{children}</div>
    )
}

export default Component

Typescript should not warn you about any errors with this approach to the problem.

Other resources on the subject

Below are links to the original discussion and some posts on this topic.

Eduardo Zepeda
Web developer and GNU/Linux enthusiast. I believe in choosing the right tool for the job and that simplicity is the ultimate sophistication. Better done than perfect. I also believe in the goodnesses of cryptocurrencies outside of monetary speculation.
Read more