React JSX의 동적 태그 이름
HTML 표제 태그용 React 컴포넌트를 작성하려고 합니다.h1,h2,h3, 등)를 사용하여 제목 레벨을 지정합니다.
이렇게 하려고 했는데
<h{this.props.level}>Hello</h{this.props.level}>
그리고 나는 다음과 같은 출력을 기대했다.
<h1>Hello</h1>
근데 이거 안 되네.
어떻게 할 수 있을까요?
내부적으로는 할 수 없습니다.변수에 입력합니다(첫 글자는 대문자로 표시).
const CustomTag = `h${this.props.level}`;
<CustomTag>Hello</CustomTag>
TypeScript 를 사용하고 있는 경우는, 다음과 같은 에러가 표시됩니다.
Type '{ children: string; }' has no properties in common with type 'IntrinsicAttributes'.ts(2559)
TypeScript는 이를 인식하지 않습니다.CustomTag는 유효한 HTML 태그명으로 도움이 되지 않는 오류를 발생시킵니다.
수정, 주조CustomTag~하듯이keyof JSX.IntrinsicElements!
// var name must start with a capital letter
const CustomTag = `h${this.props.level}` as keyof JSX.IntrinsicElements;
<CustomTag>Hello</CustomTag>
완전성을 위해 동적 이름을 사용하는 경우 JSX를 사용하는 대신 직접 호출할 수도 있습니다.
React.createElement(`h${this.props.level}`, null, 'Hello')
이렇게 하면 새 변수 또는 구성 요소를 생성할 필요가 없습니다.
소품 포함:
React.createElement(
  `h${this.props.level}`,
  {
    foo: 'bar',
  },
  'Hello'
)
문서에서:
지정된 유형의 새 React 요소를 만들고 반환합니다.type 인수에는 태그 이름 문자열(예:
'div'또는'span'또는 React 컴포넌트 유형(클래스 또는 함수).JSX로 작성된 코드가 사용되도록 변환됩니다.
React.createElement(). 일반적으로는 를 호출하지 않습니다.React.createElement()JSX 를 사용하고 있는 경우는, 직접 참조해 주세요.자세한 내용은 JSX 없이 대응을 참조하십시오.
다른 답변은 모두 정상적으로 동작하고 있습니다만, 몇 가지 추가하겠습니다.이렇게 하면 다음과 같이 됩니다.
- 조금 더 안전합니다.타입 체크에 실패해도 적절한 컴포넌트를 반송합니다.
- 그것은 더 선언적이다.이 컴포넌트를 보면 누구나 무엇을 반환할 수 있는지 알 수 있습니다.
- 예를 들어 'h1', 'h2' 대신 'sm', 'lg' 또는 'primary', 'secondary'라는 다른 추상 개념을 사용할 수 있습니다.
Heading 컴포넌트:
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;
어떤 식으로 사용할 수 있습니까?
<Heading type="h1">Some Heading</Heading>
또는 다음과 같은 크기 소품을 정의할 수 있습니다.
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;
어떤 식으로 사용할 수 있습니까?
<Heading size="sm">Some Heading</Heading>
동적 머리글(h1, h2...)의 경우 구성요소가 반환될 수 있습니다.React.createElement(위에서 펠릭스에 의해 언급됨) 이렇게.
const Heading = ({level, children, ...props}) => {
    return React.createElement('h'.concat(level), props , children)
}
컴포넌트는 소품도 아이도 패스합니다.
제 프로젝트를 위해 이렇게 셋업했습니다.
타이포그래피 타입.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';
};
타이포그래피.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;
한번 시도해 보세요.저는 이렇게 구현합니다.
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);
robstarbuck의 답변을 일반화하면 다음과 같은 완전히 동적인 태그 구성 요소를 만들 수 있습니다.
const Tag = ({ tagName, children, ...props }) => (
  React.createElement(tagName, props , children)
)
다음과 같이 사용할 수 있습니다.
const App = ({ myTagName = 'h1' }) => {
  return (
    <Tag tagName={myTagName} className="foo">
     Hello Tag!
    </Tag>
  )
}
언급URL : https://stackoverflow.com/questions/33471880/dynamic-tag-name-in-react-jsx
'programing' 카테고리의 다른 글
| InnoDB: XXX.ibd 파일의 147456 바이트 사전 할당이 오류 2로 인해 실패했습니다. (0) | 2022.10.10 | 
|---|---|
| SQL: 하나의 문으로 여러 그룹화 (0) | 2022.10.10 | 
| Maven을 사용할 때 보다 엄격한 Java 8 Javadoc을 사용하는 방법 (0) | 2022.10.10 | 
| Java 8 스트림의 .min() 및 .max(): 컴파일 이유는 무엇입니까? (0) | 2022.10.10 | 
| Python 프로세스에서 사용된 총 메모리 수? (0) | 2022.10.10 |