Nom de balise dynamique dans jsx et React

163

J'essaye d'écrire un composant React. pour les balises d'en-tête html (h1, h2, h3, etc ...), où la priorité de l'en-tête change dynamiquement en fonction de la priorité que nous avons définie dans les accessoires.

Voici ce que j'essaye de faire.

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

production attendue:

<h1>Hello</h1>

Cela ne fonctionne pas. Existe-t-il une méthode possible pour le faire?

Eranga Kapukotuwa
la source
Double possible des noms de composants dynamiques React / JSX
Jordan Running

Réponses:

329

Pas moyen de le faire sur place, il suffit de le mettre dans une variable ( avec la première lettre en majuscule ):

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

<CustomTag>Hello</CustomTag>
zerkms
la source
5
Certainement plus facile que React.createClass, je préfère cette façon. Merci.
Vadorequest
@zerkms Avez-vous une idée de comment ajouter des attributs à CustomTag? merci
Sabrina Luo
1
@Sabrina<CustomTag foo="bar">
zerkms
Huh. Comment cela marche-t-il? Si le nom de la variable est en minuscules, il insère simplement cela en tant que balise (par exemple, si c'était customtag, j'obtiendrais <customtag> Hello </customtag>). Est-ce documenté quelque part?
Ibrahim
5
Si le composant est stocké dans la propriété d'un objet, une première lettre majuscule n'est pas nécessaire. var foo = { bar: CustomTag }; return <foo.bar />fonctionne très bien.
jdunning
29

Par souci d'exhaustivité, si vous souhaitez utiliser un nom dynamique, vous pouvez également appeler directement React.createElementau lieu d'utiliser JSX:

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

Cela évite d'avoir à créer une nouvelle variable ou un nouveau composant.

Avec des accessoires:

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

À partir de la documentation :

Créez et retournez un nouvel élément React du type donné. L'argument type peut être soit une chaîne de nom de balise (telle que 'div'ou 'span'), soit un type de composant React (une classe ou une fonction).

Le code écrit avec JSX sera converti pour être utilisé React.createElement(). Vous n'invoquerez généralement pas React.createElement()directement si vous utilisez JSX. Voir Réagir sans JSX pour en savoir plus.

Félix Kling
la source
11

Si vous utilisez TypeScript, vous aurez vu une erreur comme celle-ci:

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

TypeScript ne sait pas que CustomTag s'agit d'un nom de balise HTML valide et génère une erreur inutile.

Pour réparer, cast CustomTagcomme keyof JSX.IntrinsicElements!

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

<CustomTag>Hello</CustomTag>
Jack Steam
la source
Je suis sur TypeScript mais le casting donne cette erreur: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'.
Can Poyrazoğlu
8

Toutes les autres réponses fonctionnent bien, mais j'ajouterais un peu plus, car en faisant ceci:

  1. C'est un peu plus sûr. Même si votre vérification de type échoue, vous renvoyez toujours un composant approprié.
  2. C'est plus déclaratif. N'importe qui en regardant ce composant peut voir ce qu'il pourrait retourner.
  3. C'est plus flexible par exemple au lieu de 'h1', 'h2', ... pour le type de votre titre, vous pouvez avoir d'autres concepts abstraits 'sm', 'lg' ou 'primary', 'secondary'

Le composant Titre:

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 vous pouvez l'utiliser comme

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

ou vous pouvez avoir un concept abstrait différent, par exemple, vous pouvez définir une taille d'accessoires comme:

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 vous pouvez l'utiliser comme

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

Dans le cas des en-têtes dynamiques (h1, h2 ...) , un composant pourrait retourner React.createElement(mentionné ci-dessus par Félix ) comme ça.

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

Pour la composabilité, les accessoires et les enfants sont passés.

Voir l'exemple

robstarbuck
la source