Nombre de etiqueta dinámica en jsx y React

163

Intento escribir un componente Reaccionar. para etiquetas de encabezado html (h1, h2, h3, etc.), donde la prioridad del encabezado cambia dinámicamente en función de la prioridad que hemos definido en los accesorios.

Aquí lo que intento hacer.

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

Rendimiento esperado:

<h1>Hello</h1>

Esto no está funcionando. ¿Hay algún método posible para hacer esto?

Eranga Kapukotuwa
fuente
Posible duplicado de los nombres de componentes dinámicos React / JSX
Jordan Running

Respuestas:

329

No hay forma de hacer eso en el lugar, simplemente póngalo en una variable ( con la primera letra en mayúscula ):

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

<CustomTag>Hello</CustomTag>
zerkms
fuente
55
Definitivamente más fácil que React.createClass, prefiero de esta manera. Gracias.
Vadorequest
@zerkms ¿Tiene alguna idea de cómo agregar atributos a CustomTag? gracias
Sabrina Luo
1
@Sabrina<CustomTag foo="bar">
zerkms
Huh ¿Como funciona esto? Si el nombre de la variable está en minúscula, simplemente lo inserta como una etiqueta (por ejemplo, si fuera una etiqueta personalizada, obtendría <customtag> Hola </customtag>). ¿Está esto documentado en alguna parte?
Ibrahim
55
Si el componente se almacena en la propiedad de un objeto, no es necesaria una primera letra mayúscula. var foo = { bar: CustomTag }; return <foo.bar />funciona bien.
Jdunning
29

Para completar, si desea usar un nombre dinámico, también puede llamar directamente en React.createElementlugar de usar JSX:

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

Esto evita tener que crear una nueva variable o componente.

Con accesorios:

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

De los documentos :

Crea y devuelve un nuevo elemento React del tipo dado. El argumento de tipo puede ser una cadena de nombre de etiqueta (como 'div'o 'span') o un tipo de componente Reaccionar (una clase o una función).

El código escrito con JSX se convertirá para usar React.createElement(). Por lo general, no invocará React.createElement()directamente si está utilizando JSX. Consulte Reaccionar sin JSX para obtener más información.

Felix Kling
fuente
11

Si está utilizando TypeScript, habrá visto un error como este:

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

TypeScript no sabe que CustomTages un nombre de etiqueta HTML válido y arroja un error inútil.

¡Para arreglar, lanzar CustomTagcomo keyof JSX.IntrinsicElements!

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

<CustomTag>Hello</CustomTag>
Jack Steam
fuente
Estoy en TypeScript pero al 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'.
emitirlo aparece
8

Todas las otras respuestas están funcionando bien, pero agregaría un poco más, porque al hacer esto:

  1. Es un poco más seguro. Incluso si su verificación de tipo falla, aún devuelve un componente adecuado.
  2. Es más declarativo. Al mirar este componente, cualquiera puede ver lo que podría devolver.
  3. Es más flexible, por ejemplo, en lugar de 'h1', 'h2', ... para el tipo de título, puede tener otros conceptos abstractos 'sm', 'lg' o 'primario', 'secundario'

El componente de encabezado:

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 puedes usar como

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

o puede tener un concepto abstracto diferente, por ejemplo, puede definir accesorios de tamaño 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 puedes usar como

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

En el caso de los encabezados dinámicos (h1, h2 ...) , un componente podría regresar React.createElement(mencionado anteriormente por Felix ) así.

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

Para la compostibilidad, se pasan los accesorios y los niños.

Ver ejemplo

robstarbuck
fuente