Índice del contenido

¿Por qué usar React.FC podria ser una mala practica?

¿Por qué usar React.FC podria ser una mala practica?

Cuando usamos Typescript con React y queremos pasarle un children como prop a alguno de nuestros componentes, necesitamos indicar el type. Generalmente se suele usar el type React.FC, el cual es el nombre abreviado de React.FunctionComponent. Con esto el mensaje de Typescript que nos advierte de un children con tipo any desaparecerá.

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

Además de permitirnos trabajar con children, React.FC también provoca un error si intentamos devolver undefined desde nuestro componente.

const Componente: React.FC = ({ children }) => {
    // El tipo '() => undefined' no se puede asignar al tipo 'FC<{}>'.
    return undefined
}

export default Componente

Como puedes ver, es bastante cómodo usarlo, pero algunas personas no están de acuerdo en su uso.

React.FC ¿más desventajas que ventajas?

¿Dónde está el problema? Pues algunos desarrolladores afirman que React.FC puede traer más desventajas que ventajas, incluso hay una discusión en github (enlace al final), en la que se debate si es conveniente remover uno de los ejemplos en la documentación que lo usa.

El usuario que inició esta discusión considera que el hecho de que React.FC sea tan popular es debido a que su presencia en la documentación lo posiciona como la manera predeterminada de manejar los componentes de React con Typescript.

Te explico a continuación algunas de las razones que se exponen para afirmar que React.FC aporta más desventajas que ventajas.

React.FC no nos avisa de children sin usar

React.FC no siempre es la manera más explícita de indicarle a typescript que un componente recibe children como parte de sus props.

Imagínate que le pasamos un children al componente, pero no lo usamos.

import Componente from './Componente';

function App() {
  return (
    <Componente>Soy el children</Componente>
  );
}

export default App;

Nuestro componente sí que recibe el children como un prop, pero el type React.FC apacigua a Typescript y evita que este nos devuelva algún error, incluso aunque no lo estemos usando.

const Componente: React.FC = () => {
    return (
        <div>No soy el children que recibe Componente</div>
    )
}

export default Componente

O, para un caso contrario; imagína que no deseamos que nuestro componente reciba un children como uno de sus props, sin embargo, como estamos usando React.FC no obtendremos ningún error.

import Componente from './Componente';

function App() {
  return (
    <Componente><div>Yo no debería de estar aquí</div></Componente>
  );
}

export default App;

El patrón de subcomponentes en React se complica

El patrón componente como namespace es bastante sencillo de crear sin usar React.FC, pero con React.FC puede complicarse bastante.

¿No sabes que es? Piensa en un patrón que te permite agrupar componentes dentro de un cierto padre, que funciona como un namespace para nuestros componentes hijos; similar a como funcionaría el namespace std de C++.

<Namespace>
	<Namespace.Componente />
</Namespace>

En su forma más sencilla, omitiendo React.FC se vería algo así:

const Namespace = (props: PropsDelNamespace) => {/* ... */}
Namespace.Componente = (props: PropsDelComponente) => { /*...*/ }

Pero si optamos por usar React.FC el código se complicaría y la legibilidad disminuiría un poco.

const  Namespace: React.FC<PropsDelNamespace> & { Componente: React.FC<PropsDelComponente> } = (props) => {/* ... */ }
Namespace.Componente = (props) => { /*...*/ }

¿Qué deberíamos usar en lugar de React.FC?

El núcleo de las críticas se basta en que React.FC añade el children de manera implícita, yendo contra la naturaleza explícita de typescript.

Sin embargo, la discusión de la que te hablo es solo eso, una discusión, no está escrita en piedra, puede que tú consideres que es mejor sacrificar un poco de legibilidad en favor de la comodidad o, por el contrario, puede que creas que es importante ser explícito cuando se trabaja con typescript.

Si es el caso, considera que siempre puedes declarar el children como un prop de manera explícita, tal como lo harías con cualquier otro prop. Y de la misma manera, puedes declarar el valor de retorno de tu componente como un elemento de tipo JSX.

interface propsWithChildren {
    children: React.ReactNode
}


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

export default Componente

Typescript no debería de advertirte sobre ningún error con esta aproximación al problema.

Otros recursos sobre el tema

Aquí abajo te dejo los enlaces a la discusión original y algunos posts al respecto de este tema.

Otros posts recomendados

Eduardo Zepeda picture

Eduardo Zepeda

Desarrollador web y entusiasta de GNU/Linux. Me siento bastante cómodo usando Python, Javascript/Typescript y Go: el odiado lenguaje de la mascotita azul. También creo en las bondades de la criptografía fuera de la especulación monetaria. Mensaje secreto en Vigenere: Yy pgkvnvm yw tvdmg k bp oqntq yonaqniomm dxzdeu. Mgz emzr, rdcyvqkanyyymm znumszl kdepfcqbkjs a ocpgkda huwnbwi. Lkzepwqi mg bucxkz swbyc izztgzwthaj y hmfdh, xjr na kfx, ad pwpcdmm gegd ydmw vgtqalfm zn Vicemmm.