Me gustaría crear un componente ConditionalWrapper para que sea más declarativo en mi aplicación.
Mi idea es usarlo de la siguiente manera
<ConditionalWrapper condition={whatever} element={<a href="my-link" />}> ...other children </ConditionalWrapper>Tengo esto hasta ahora, pero obviamente no está funcionando, y realmente no puedo ver dónde me equivoco.
interface ConditionalWrapperProps { condition: boolean children?: React.ReactNode element: React.ReactElement defaultElement?: React.ReactElement } const ConditionalWrapper = ({ condition, children, element, defaultElement }: ConditionalWrapperProps): JSX.Element => { const Element = (Wrapper): JSX.Element => <Wrapper>{children}</Wrapper> return condition ? ( <Element Wrapper={element}>{children}</Element> ) : ( <Element Wrapper={defaultElement || Fragment}>{children}</Element> ) } El error que recibo en este momento es Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object .
Está claro que mis tipos y lógica son incorrectos, pero también probé diferentes variaciones sin éxito. ¿Alguna sugerencia?
Necesitas hacer varias cosas. En primer lugar, su función Element no es en realidad un componente de función React válido.
Luego, debe aceptar parámetros que son componentes de funciones y aún no elementos.
He separado el Element en su propio ámbito llamado ElementWrapper , solo para comprender cómo los parámetros eran incorrectos. Por supuesto, puede mover esto de nuevo al ConditionalWrapper .
También tendrá que mover la lógica del fragmento a otro lugar, ya que Fragment no es un componente de función.
interface ConditionalWrapperProps { condition: boolean; children?: React.ReactNode; element: React.FunctionComponent; //These need to be FunctionComponents defaultElement?: React.FunctionComponent; } //Here you can see you forgot to have a children property const ElementWrapper = (props: { Wrapper: React.FunctionComponent; children: React.ReactNode; }): JSX.Element => <props.Wrapper>{props.children}</props.Wrapper>; const ConditionalWrapper = ({ condition, children, element, defaultElement, }: ConditionalWrapperProps): JSX.Element => { return condition ? ( <ElementWrapper wrapper={element>{children}</ElementWrapper> ) : DefaultElement ? ( <ElementWrapper Wrapper={defaultElement}>{children}</ElementWrapper> ) : ( <>{children}</> ); ); };Personalmente, no creo que necesite la función de clase ElementWrapper, solo llame a los componentes de función directamente en ConditionalWrapper, así. Las propiedades se renombran para seguir las pautas de que React Elements debe tener nombres en mayúsculas.
const ConditionalWrapper = ({ condition, children, WrapperElement, DefaultElement, }: ConditionalWrapperProps): JSX.Element => { return condition ? ( <WrapperElement>{children}</WrapperElement> ) : DefaultElement ? ( <DefaultElement>{children}</DefaultElement> ) : ( <>{children}</> ); };Si define su función como const Element = (Wrapper):... --> Wrapper se refiere a las propiedades del elemento, no a la propiedad Wrapper , cambiando a const Element = ({Wrapper}):... funcionará.
Creo que puede acortar su código y ahorrar algunas líneas haciendo esto:
const ConditionalWrapper = ({ condition, children, element, defaultElement }: ConditionalWrapperProps): JSX.Element => { const Wrapper = condition ? element : defaultElement || Fragment; return (<Wrapper>{children}</Wrapper>) }