Динамическое имя тега в jsx и React

163

Я пытаюсь написать компонент React. для тегов заголовков html (h1, h2, h3 и т. д.), где приоритет заголовка динамически изменяется в зависимости от приоритета, который мы определили в подпорках.

Вот что я пытаюсь сделать.

<h{this.props.priority}>Hello</h{this.props.priority}>

ожидаемый результат:

<h1>Hello</h1>

Это не работает. Есть ли какой-нибудь возможный способ сделать это?

Эранга Капукотува
источник
Возможные дубликаты имен динамических компонентов React / JSX
Джордан,

Ответы:

329

Нет способа сделать это на месте, просто поместите его в переменную ( с заглавной буквой ):

const CustomTag = `h${this.props.priority}`;

<CustomTag>Hello</CustomTag>
zerkms
источник
5
Определенно проще, чем React.createClassя предпочитаю. Спасибо.
Vadorequest
@zerkms У вас есть идеи, как добавить атрибуты в CustomTag? спасибо
Сабрина Ло
1
@Sabrina<CustomTag foo="bar">
zerkms
Да. Как это работает? Если имя переменной в нижнем регистре, она просто вставляет это как тег (например, если бы это был customtag, я бы получил <customtag> Hello </ customtag>). Это где-нибудь задокументировано?
Ибрагим
5
Если компонент хранится в свойстве объекта, заглавная первая буква не требуется. var foo = { bar: CustomTag }; return <foo.bar />работает отлично.
июня 18
29

Для полноты, если вы хотите использовать динамическое имя, вы также можете напрямую вызвать React.createElementвместо использования JSX:

React.createElement(`h${this.props.priority}`, null, 'Hello')

Это избавляет от необходимости создавать новую переменную или компонент.

С реквизитом:

React.createElement(
  `h${this.props.priority}`,
  {
    foo: 'bar',
  },
  'Hello'
)

Из документов :

Создайте и верните новый элемент React данного типа. Аргументом типа может быть либо строка имени тега (например, 'div'или 'span'), либо тип компонента React (класс или функция).

Код, написанный с помощью JSX, будет преобразован для использования React.createElement(). Как правило, вы не будете вызывать React.createElement()напрямую, если вы используете JSX. Смотрите React Without JSX, чтобы узнать больше.

Феликс Клинг
источник
11

Если вы используете TypeScript, вы увидите такую ​​ошибку:

Type '{ children: string; }' has no properties in common with type 'IntrinsicAttributes'.ts(2559)

TypeScript не знает, что CustomTagявляется допустимым именем тега HTML, и выдает бесполезную ошибку.

Чтобы исправить, бросьте CustomTagкак keyof JSX.IntrinsicElements!

const CustomTag = `h${this.props.priority}` as keyof JSX.IntrinsicElements;

<CustomTag>Hello</CustomTag>
Джек Стим
источник
Я нахожусь на TypeScript, но приведение дает это сообщение об ошибке:Types of property 'crossOrigin' are incompatible. Type 'string | undefined' is not assignable to type '"" | "anonymous" | "use-credentials" | undefined'. Type 'string' is not assignable to type '"" | "anonymous" | "use-credentials" | undefined'.
Может Poyrazoğlu
8

Все остальные ответы работают нормально, но я бы добавил несколько дополнительных, потому что, делая это:

  1. Это немного безопаснее. Даже если ваша проверка типов не удалась, вы все равно вернете подходящий компонент.
  2. Это более декларативно. Любой, посмотрев на этот компонент, может увидеть, что он может вернуть.
  3. Он более гибок, например, вместо «h1», «h2», ... для типа вашего заголовка вы можете использовать некоторые другие абстрактные понятия «sm», «lg» или «primary», «second»

Заголовок компонента:

import React from 'react';

const elements = {
  h1: 'h1',
  h2: 'h2',
  h3: 'h3',
  h4: 'h4',
  h5: 'h5',
  h6: 'h6',
};

function Heading({ type, children, ...props }) {    
  return React.createElement(
    elements[type] || elements.h1, 
    props, 
    children
  );
}

Heading.defaultProps = {
  type: 'h1',
};

export default Heading;

Который вы можете использовать как

<Heading type="h1">Some Heading</Heading>

или вы можете иметь другую абстрактную концепцию, например, вы можете определить размер реквизита как:

import React from 'react';

const elements = {
  xl: 'h1',
  lg: 'h2',
  rg: 'h3',
  sm: 'h4',
  xs: 'h5',
  xxs: 'h6',
};

function Heading({ size, children }) {
  return React.createElement(
    elements[size] || elements.rg, 
    props, 
    children
  );
}

Heading.defaultProps = {
  size: 'rg',
};

export default Heading;

Который вы можете использовать как

<Heading size="sm">Some Heading</Heading>
Саман Шафиг
источник
2

В случае динамических заголовков (h1, h2 ...) компонент может возвращаться React.createElement(упомянутый выше Феликсом ) следующим образом.

const Heading = ({level, children, ...props}) => {
    return React.createElement(`h${level}`, props , children)
}

Для компоновки пропускаются как реквизиты, так и дети.

См пример

robstarbuck
источник