Dynamiczna nazwa tagu w jsx i React


162

Próbuję napisać komponent React. dla tagów nagłówków html (h1, h2, h3, itd.), gdzie priorytet nagłówka zmienia się dynamicznie w zależności od priorytetu, który zdefiniowaliśmy we właściwościach.

Oto co próbuję zrobić.

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

oczekiwany wynik:

<h1>Hello</h1>

To nie działa. Czy jest na to jakikolwiek sposób?


Odpowiedzi:


328

Nie ma sposobu, aby to zrobić na miejscu, po prostu umieść go w zmiennej ( z wielką literą ):

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

<CustomTag>Hello</CustomTag>

5
Zdecydowanie łatwiejsze niż React.createClass, wolę ten sposób. Dzięki.
Vadorequest

@zerkms Czy masz pomysł, jak dodać atrybuty do CustomTag? dzięki
Sabrina Luo

1
@Sabrina<CustomTag foo="bar">
zerkms

Huh. Jak to działa? Jeśli nazwa zmiennej jest zapisana małymi literami, po prostu wstawia ją jako tag (np. Gdyby był to tag niestandardowy, otrzymywałbym <customtag> Hello </customtag>). Czy jest to gdzieś udokumentowane?
Ibrahim,

5
Jeśli składnik jest przechowywany we właściwości obiektu, wielka pierwsza litera nie jest konieczna. var foo = { bar: CustomTag }; return <foo.bar />działa w porządku.
jdunning

29

Dla kompletności, jeśli chcesz użyć dynamicznej nazwy, możesz również bezpośrednio wywołać React.createElementzamiast używania JSX:

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

Pozwala to uniknąć konieczności tworzenia nowej zmiennej lub komponentu.

Z rekwizytami:

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

Z dokumentów :

Utwórz i zwróć nowy element React podanego typu. Argument type może być ciągiem znaków z nazwą znacznika (na przykład 'div'lub 'span') lub typem składnika React (klasa lub funkcja).

Kod napisany w JSX zostanie przekonwertowany do użycia React.createElement(). Zwykle nie będziesz wywoływać React.createElement()bezpośrednio, jeśli używasz JSX. Zobacz Reaguj bez JSX, aby dowiedzieć się więcej.


11

Jeśli używasz TypeScript, zobaczysz następujący błąd:

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

TypeScript nie wie, czy CustomTagjest to prawidłowa nazwa tagu HTML, i zgłasza nieprzydatny błąd.

Aby naprawić, przesyłaj CustomTagjakokeyof JSX.IntrinsicElements !

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

<CustomTag>Hello</CustomTag>

Jestem na TypeScript, ale przesyłanie go powoduje ten błąd: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

Wszystkie inne odpowiedzi działają dobrze, ale dodałbym kilka dodatkowych, ponieważ robiąc to:

  1. To jest trochę bezpieczniejsze. Nawet jeśli sprawdzanie typu kończy się niepowodzeniem, nadal zwracasz właściwy składnik.
  2. Jest bardziej deklaratywny. Każdy, patrząc na ten komponent, może zobaczyć, co może zwrócić.
  3. Jest bardziej elastyczny na przykład zamiast 'h1', 'h2', ... dla typu twojego nagłówka możesz mieć inne abstrakcyjne pojęcia 'sm', 'lg' lub 'podstawowy', 'drugorzędny'

Komponent Nagłówek:

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;

Którego możesz użyć

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

lub możesz mieć inną abstrakcyjną koncepcję, na przykład możesz zdefiniować rekwizyty rozmiaru, takie jak:

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;

Którego możesz użyć

<Heading size="sm">Some Heading</Heading>

2

W przypadku nagłówków dynamicznych (h1, h2 ...) , komponent mógłby powrócić React.createElement(o czym wspomniał Felix ) w ten sposób.

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

W przypadku możliwości komponowania przekazywane są zarówno rekwizyty, jak i elementy podrzędne.

Zobacz przykład

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.