Nome da tag dinâmica em jsx e React

162

Eu tento escrever um componente React. para tags de cabeçalho html (h1, h2, h3, etc ...), em que a prioridade do cabeçalho muda dinamicamente com base na prioridade que definimos nos adereços.

Aqui o que eu tento fazer.

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

resultado esperado:

<h1>Hello</h1>

Isto não está a funcionar. Existe algum método possível para fazer isso?

Eranga Kapukotuwa
fonte
Possível duplicata de nomes de componentes dinâmicos React / JSX
Jordan Running

Respostas:

328

Não há como fazer isso no local, basta colocá-lo em uma variável ( com a primeira letra maiúscula ):

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

<CustomTag>Hello</CustomTag>
zerkms
fonte
5
Definitivamente mais fácil do que React.createClasseu prefiro assim. Obrigado.
Vadorequest
@zerkms Você tem alguma idéia de como adicionar atributos à CustomTag? obrigado
Sabrina Luo
1
@Sabrina<CustomTag foo="bar">
zerkms
Hã. Como é que isso funciona? Se o nome da variável estiver em letras minúsculas, ele será inserido apenas como uma tag (por exemplo, se fosse o rótulo da região, eu receberia <customtag> Olá </customtag>). Isso está documentado em algum lugar?
Ibrahim
5
Se o componente estiver armazenado na propriedade de um objeto, uma primeira letra maiúscula não será necessária. var foo = { bar: CustomTag }; return <foo.bar />funciona bem.
Jdunning
29

Para React.createElementgarantir a integridade, se você quiser usar um nome dinâmico, também poderá ligar diretamente em vez de usar JSX:

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

Isso evita a necessidade de criar uma nova variável ou componente.

Com adereços:

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

Dos documentos :

Crie e retorne um novo elemento React do tipo especificado. O argumento type pode ser uma string de nome de tag (como 'div'or 'span') ou um tipo de componente React (uma classe ou uma função).

O código escrito com JSX será convertido para uso React.createElement(). Você normalmente não invocará React.createElement()diretamente se estiver usando JSX. Consulte Reagir sem JSX para saber mais.

Felix Kling
fonte
11

Se você estiver usando o TypeScript, verá um erro como este:

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

O TypeScript não sabe que CustomTagé um nome de marca HTML válido e gera um erro inútil.

Para consertar, use CustomTagcomo keyof JSX.IntrinsicElements!

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

<CustomTag>Hello</CustomTag>
Jack Steam
fonte
Estou no TypeScript, mas a transmissão dá o seguinte erro: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

Todas as outras respostas estão funcionando bem, mas gostaria de acrescentar algumas extras, pois, ao fazer isso:

  1. É um pouco mais seguro. Mesmo se sua verificação de tipo estiver falhando, você ainda retornará um componente adequado.
  2. É mais declarativo. Qualquer pessoa olhando para este componente pode ver o que ele poderia retornar.
  3. É mais flexível, por exemplo, em vez de 'h1', 'h2', ... para o tipo de cabeçalho, você pode ter outros conceitos abstratos 'sm', 'lg' ou 'primário', 'secundário'

O componente Título:

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;

Que você pode usar como

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

ou você pode ter um conceito abstrato diferente, por exemplo, pode definir adereços de tamanho como:

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;

Que você pode usar como

<Heading size="sm">Some Heading</Heading>
Saman Shafigh
fonte
2

No caso de títulos dinâmicos (h1, h2 ...) , um componente pode retornar React.createElement(mencionado acima por Felix ) assim.

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

Para composição, adereços e filhos são aprovados.

Consultar exemplo

robstarbuck
fonte