Создать html-элемент, описание которого пришло из props, React

Есть компонент, который принимает проп elem, и а сам компонент должен обернуть в него свой вывод или во фрагмент, если проп не пришёл. Подобный механизм есть в Material-UI.

<Show elem="div" />

Должно вывывести:

<div>/* Some Stuff Here */</div>

а это:

<Show />

Вернёт фрагмент:

/* Some Stuff Here */

Ещё пример:

<Show elem="ol">
<li>One</li>
<li>Two</li>
</Show>

Вывод:

<ol>
<li>One</li>
<li>Two</li>
</ol>

Ответы (4 шт):

Автор решения: MrYogurt

Если я вас правильно понял, то вы хотите из родительского компонента передать пропс для отрисовки чего либо, если он приходит. Вы можете просто воспользоваться проверкой пропса на этапе рендера:

const Parent = () => {

  return (
      <Show content="Something text" />
  )
}


const Show = ({content}) => {

  return content ? (<div>{content}</div>) : null
}

Альтернативный пример рендера на основе пропса:

const Show = (htmlElement) => {

  const renderElement = (ChildComponent) => {
    if (htmlElement === "ol") { // проверяем пришедший пропс
      return <ol><ChildComponent /></ol> // возвращаем собранный компонент (если вариантов тегов будет 3 и больше, рекомендую использовать switch case)
    }
  }

  return (
    renderElement(<li />) // вызываем функцию renderElement и передаем ей дочерний компонент, который хотим положить внутрь пропсового элемента
  )
}
→ Ссылка
Автор решения: Igor Vasiliev

Может быть я вас не правильно понял, однако предположу, что вы хотите создавать парные теги, обёртку вокруг контента:

import React, {Fragment} from 'react'

export function Show({ title = '/* Some Stuff Here */', tag }) {
    return (
        <>
           {tag ? 
           React.createElement(tag, '', title) : 
           <Fragment>{title}</Fragment>}
        </>
    )

}

Получается, что вы можете полностью управлять внешними данными компонента, его тегами, пропсами, атрибутами и так далее: React.createElement(component, props, ...children)

→ Ссылка
Автор решения: Grundy

Переданный пропс можно использовать в jsx. При этом переменная должна начинаться с большой буквы, чтобы была разобрана как реакт компонент.

const {createRoot} = ReactDOM;
const {useState, Fragment} = React;

// Пример функционального компонента
const Wrapper = ({tag=Fragment, children})=>{
  const Component = tag;
  return <div>
   Wrapper
   <Component>{children}</Component>
  </div>
}

// Пример классового компонента
class App extends React.Component {
  render() {
    return (
      <React.Fragment>
        <Wrapper tag="div">
          Content 1
        </Wrapper>
        <Wrapper>
          Content 2
        </Wrapper>
      </React.Fragment>
    );
  }
}

// Рендеринг
const rootContainer = document.querySelector('#react');
const root = createRoot(rootContainer);

root.render(<App />);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

→ Ссылка
Автор решения: Евгений

Если кому-то пригодиться, сам я уже не помню, зачем мне это было нужно =):

const { createRoot } = ReactDOM;
const { createElement, Fragment } = React;

const Show = ({
  el,
  children,
  ...restProps
}) => {
  if (!el) {
    return <Fragment>{children}</Fragment>;
  }
  return createElement(el, restProps, children);
};

const HighlightComponent = ({
  bg = "#000000",
  fg = "#ffffff",
  children,
}) => {
  return <div style={{ color: fg, backgroundColor: bg }}>{children}</div>;
};


function App() {
  return (
    <Show el="div" className="App">
      <Show el="h1">Hello World!</Show>
      <Show el={HighlightComponent} bg="#aaaa00" fg="#000000">Test custom component</Show>
      <Show>Test fragment</Show>
    </Show>
  );
}

const rootContainer = document.querySelector('#react');
const root = createRoot(rootContainer);

root.render(<App />);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

→ Ссылка