Dynamischer Tag-Name in React JSX

Lesezeit: 6 Minuten

Benutzer-Avatar
Eranga Kapukotuwa

Ich versuche, eine React-Komponente für HTML-Überschriften-Tags zu schreiben (h1, h2, h3usw.), wobei die Überschriftsebene über eine Stütze angegeben wird.

Ich habe versucht, es so zu machen:

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

Und ich erwartete eine Ausgabe wie:

<h1>Hello</h1>

Aber das funktioniert nicht.

Gibt es eine Möglichkeit, dies zu tun?

Benutzer-Avatar
zerkms

Keine Möglichkeit, dies direkt zu tun, fügen Sie es einfach in eine Variable ein (mit großem Anfangsbuchstaben):

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

<CustomTag>Hello</CustomTag>

  • Definitiv einfacher als React.createClass, Ich bevorzuge diesen Weg. Vielen Dank.

    – Vadoranfrage

    6. Januar 2017 um 9:19 Uhr

  • @zerkms Hast du eine Idee, wie man Attribute zu CustomTag hinzufügt? Danke

    – Sabrina Luo

    19. Mai 2017 um 8:04 Uhr

  • @Sabrina <CustomTag foo="bar">

    – zerkms

    19. Mai 2017 um 8:08 Uhr

  • Ich denke, es liegt daran, dass mit einem großen Anfangsbuchstaben es wird als React-Komponente interpretiert, und HTML-Tag-Namen werden ebenfalls als gültige React-Komponenten angesehen, damit es funktioniert. Scheint ein wenig faul, aber ich nehme es.

    – Ibrahim

    13. September 2017 um 2:38 Uhr

  • Wenn die Komponente in der Eigenschaft eines Objekts gespeichert ist, ist ein großer Anfangsbuchstabe nicht erforderlich. var foo = { bar: CustomTag }; return <foo.bar /> funktioniert gut.

    – jMahnung

    19. Mai 2018 um 21:59 Uhr

Benutzer-Avatar
Jack Dampf

Wenn Sie TypeScript verwenden, haben Sie einen Fehler wie diesen gesehen:

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

TypeScript kennt das nicht CustomTag ein gültiger HTML-Tag-Name ist und einen nicht hilfreichen Fehler ausgibt.

Zum Reparieren, Gießen CustomTag wie keyof JSX.IntrinsicElements!

// var name must start with a capital letter
const CustomTag = `h${this.props.level}` as keyof JSX.IntrinsicElements;

<CustomTag>Hello</CustomTag>

  • Ich bin auf TypeScript, aber beim Casting gibt es diesen Fehler: 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'.

    – Kann Poyrazoğlu

    9. März 2020 um 9:25 Uhr

  • Ich wollte nur Danke dafür sagen. Ich hätte wahrscheinlich Stunden damit verbracht, dies zu schreiben, wenn dies nicht hier wäre.

    – Kelly Copley

    17. Februar 2021 um 16:24 Uhr

  • Wie können Sie dies mit Flow tun?

    – Farid Schokri

    13. Juli 2021 um 18:10 Uhr

  • Ich finde const Tag: keyof JSX.IntrinsicElements = `h${level}`; wäre etwas besser, denn wenn Sie jetzt ein ungültiges Tag verwenden, z headline${level} TypeScript wird sich beschweren. (vorausgesetzt, dass level korrekt als Literaltyp typisiert wird)

    – Martin Böttcher

    10. Januar um 8:49 Uhr


  • Beachten Sie, dass die Variable anscheinend PascalCased sein muss, damit dies funktioniert. Ich habe es versucht customTag und habe immer noch den gleichen Fehler, aber ändere es zu CustomTag alles behoben. Ich denke, Typoskript geht wahrscheinlich davon aus, dass Tags in Kleinbuchstaben native HTML-Elemente sein müssen, und validiert sie anders

    – Jemar Jones

    17. Januar um 23:35 Uhr

Benutzer-Avatar
Felix Klinge

Der Vollständigkeit halber, wenn Sie einen dynamischen Namen verwenden möchten, können Sie auch direkt anrufen React.createElement anstatt JSX zu verwenden:

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

Dadurch wird vermieden, dass eine neue Variable oder Komponente erstellt werden muss.

Mit Requisiten:

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

Von dem Dokumente:

Erstellt ein neues React-Element des angegebenen Typs und gibt es zurück. Das Typargument kann entweder eine Tag-Namenszeichenfolge (wie z 'div' oder 'span') oder ein React-Komponententyp (eine Klasse oder eine Funktion).

Mit JSX geschriebener Code wird zur Verwendung konvertiert React.createElement(). Sie werden normalerweise nicht aufgerufen React.createElement() direkt, wenn Sie JSX verwenden. Sehen Reagieren ohne JSX um mehr zu lernen.

Benutzer-Avatar
Saman

Alle anderen Antworten funktionieren einwandfrei, aber ich würde einige zusätzliche hinzufügen, denn auf diese Weise:

  1. Es ist etwas sicherer. Selbst wenn Ihre Typprüfung fehlschlägt, senden Sie dennoch eine ordnungsgemäße Komponente zurück.
  2. Es ist deklarativer. Jeder, der sich diese Komponente ansieht, kann sehen, was sie zurückgeben könnte.
  3. Es ist flexibler, zum Beispiel anstelle von ‘h1’, ‘h2’, … für den Typ Ihrer Überschrift können Sie einige andere abstrakte Konzepte haben ‘sm’, ‘lg’ oder ‘primary’, ‘secondary’

Die Heading-Komponente:

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;

Die kannst du gerne verwenden

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

oder Sie können ein anderes abstraktes Konzept haben, zum Beispiel können Sie eine Größenrequisite definieren wie:

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;

Die kannst du gerne verwenden

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

Im Fall dynamischer Überschriften (h1, h2…)könnte eine Komponente zurückkehren React.createElement (oben erwähnt von Felix) so.

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

Für die Zusammensetzbarkeit werden sowohl Requisiten als auch untergeordnete Elemente übergeben.

Siehe Beispiel

So habe ich es für mein Projekt eingerichtet.

TypographyType.ts

import { HTMLAttributes } from 'react';

export type TagType="h1" | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span';

export type HeadingType = HTMLAttributes<HTMLHeadingElement>;
export type ParagraphType = HTMLAttributes<HTMLParagraphElement>;
export type SpanType = HTMLAttributes<HTMLSpanElement>;

export type TypographyProps = (HeadingType | ParagraphType | SpanType) & {
  variant?:
    | 'h1'
    | 'h2'
    | 'h3'
    | 'h4'
    | 'h5'
    | 'h6'
    | 'body1'
    | 'body2'
    | 'subtitle1'
    | 'subtitle2'
    | 'caption'
    | 'overline'
    | 'button';
};

Typografie.tsx

    import { FC } from 'react';
    import cn from 'classnames';
    import { typography } from '@/theme';
    
    import { TagType, TypographyProps } from './TypographyType';
    
    const headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
    const paragraphs = ['body1', 'body2', 'subtitle1', 'subtitle2'];
    const spans = ['button', 'caption', 'overline'];
    
    const Typography: FC<TypographyProps> = ({
      children,
      variant="body1",
      className,
      ...props
    }) => {
      const { variants } = typography;
    
      const Tag = cn({
        [`${variant}`]: headings.includes(variant),
        [`p`]: paragraphs.includes(variant),
        [`span`]: spans.includes(variant)
      }) as TagType;
    
      return (
        <Tag
          {...props}
          className={cn(
            {
              [`${variants[variant]}`]: variant,
            },
            className
          )}
        >
          {children}
        </Tag>
      );
    };
    
    export default Typography;

Benutzer-Avatar
ashwin1014

Sie können dies versuchen. Ich setze so um.

import { memo, ReactNode } from "react";
import cx from "classnames";

import classes from "./Title.module.scss";

export interface TitleProps {
  children?: ReactNode;
  className?: string;
  text?: string;
  variant: Sizes;
}

type Sizes = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
const Title = ({
  className,
  variant = "h1",
  text,
  children,
}: TitleProps): JSX.Element => {
  const Tag = `${variant}` as keyof JSX.IntrinsicElements;
  return (
    <Tag
      className={cx(`${classes.title} ${classes[variant]}`, {
        [`${className}`]: className,
      })}
    >
      {text || children}
    </Tag>
  );
};

export default memo(Title);

1310610cookie-checkDynamischer Tag-Name in React JSX

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy