reactjs - ¿Cómo conviertes `props.children` en un elemento JSX?
Con los componentes funcionales de React, podemos renderizar hijos así:
import React from 'react';
const MyComponent = (props: React.PropsWithChildren) => {
return props.children;
}
Sin embargo, cuando intento usar esto, me aparece un error:
...
return <MyComponent />;
...
o
...
return (
<MyComponent>
<div>hello</div>
</MyComponent>
);
...
conduce a
'MyComponent' cannot be used as a JSX component. Its return type 'ReactNode' is not a valid JSX element. Type 'undefined' is not assignable to type 'Element | null'.
Una solución es envolver el valor devuelto por el componente funcional en un fragmento:
const MyComponent = (props: React.PropsWithChildren) => {
return <>{props.children}</>; // <= useless fragment is here
}
Sin embargo, luego desencadeno el error eslint: react/jsx-no-useless-fragment.
¿Hay alguna manera de usar a los niños de tal manera que no tenga ninguno de estos problemas?
Editar
Aquí hay un enlace a un parque de juegos
¿Existe una manera de convertir un ReactNode en un componente JSX válido aparte de usar un fragmento?
Nota Adicional: eslint-plugin-react tiene una opción para allowExpressions que cubre este caso de uso. Esencialmente, permitirá fragmentos "inútiles" cuando el fragmento esté realizando el trabajo de conversión de ReactNode => elemento JSX.
Respuesta #1
El fragmento "inútil" es en realidad lo mismo que llamar
React.createElement(React.Fragment, null, props.children);
React.createElement es capaz de usar un tipo de componente (React.Fragment) y elementos hijos para crear un elemento JSX de ese tipo con esos hijos.
Entonces la solución es hacer esto:
const MyComponent = (props: React.PropsWithChildren) => {
return React.createElement(React.Fragment, null, props.children);
}
Eso hace felices tanto a TS como a eslint. Sin embargo, JSX es preferido sobre createElement. Habilitar la opción {"allowExpressions": true} para la regla de eslint (ver la pregunta para más detalles) y usar un fragmento al estilo JSX es la mejor opción aquí.
Gracias a todos por la ayuda.
Respuesta #2
Veo aquí 2 puntos importantes:
La revisión que proporcionaste en tu último bloque de código con los children envueltos en un fragmento es importante en Typescript. Los children pueden ser un array de elementos, lo cual no sería un elemento válido, por lo que necesita estar envuelto en un elemento válido para cubrir ese caso (o verificarse para asegurar que no sea un array). (Al menos en Typescript y React antes de la v16.)
La regla de eslint que mencionas y que causa el segundo error se activa porque solo hay un elemento dentro del fragmento. Sin embargo, dado que eso es lo que queremos para cumplir con la definición de Typescript, eso es problemático. Recomendaría silenciar ese error en este caso específico.
Una opción es agregar un comentario de desactivación en la línea antes del return de esta manera:
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{props.children}</>;
