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


163

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

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

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

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

<h1>Hello</h1>

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


Ответы:


329

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

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

<CustomTag>Hello</CustomTag>

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)
}

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

См пример

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.