jsx和React中的动态标记名称

时间:2015-11-02 06:26:57

标签: node.js react-jsx

我尝试编写一个React组件。对于html标题标签(h1,h2,h3等等),其中标题优先级根据我们在道具中定义的优先级动态变化。

这是我尝试做的事情。

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

预期产出:

<h1>Hello</h1>

这不起作用。有没有可行的方法呢?

7 个答案:

答案 0 :(得分:244)

无法就地执行此操作,只需将其放入变量(with first letter capitalised)中:

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

<CustomTag>Hello</CustomTag>

答案 1 :(得分:26)

如果您使用的是TypeScript,则会看到这样的错误:

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

TypeScript不知道CustomTag是有效的HTML标记名称,并抛出无用的错误。

要解决此问题,请将CustomTag强制转换为keyof JSX.IntrinsicElements

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

<CustomTag>Hello</CustomTag>

答案 2 :(得分:19)

为了完整性,如果你想使用动态名称,你也可以直接调用React.createElement而不是使用JSX:

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

这可以避免必须创建新的变量或组件。

使用道具:

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

来自docs

  

创建并返回给定类型的新React元素。 type参数可以是标记名称字符串(例如'div''span'),也可以是React组件类型(类或函数)。

     

使用JSX编写的代码将转换为使用React.createElement()。如果您使用的是JSX,通常不会直接调用React.createElement()。请参阅React Without JSX了解详情。

答案 3 :(得分:2)

在动态标题(h1,h2 ...)的情况下,组件可以返回React.createElement(上面提到Felix),如此。

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

对于可组合性,道具和儿童都会被传递。

See Example

答案 4 :(得分:1)

你可以试试这个。我是这样实现的。

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);

答案 5 :(得分:0)

所有其他答案都工作正常,但我会添加一些其他内容,因为这样做:

  1. 这比较安全。即使您的类型检查失败了,您仍然 返回适当的组件。
  2. 更具声明性。通过查看此组件的任何人都可以看到它可以返回什么。
  3. 例如,它更灵活,而不是“ h1”,“ h2”……对于标题的类型,您可以具有其他一些抽象概念“ sm”,“ lg”或“ primary”,“ secondary” < / li>

标题组件:

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>

答案 6 :(得分:0)

只想补充一点,如果它们是自定义组件,例如<Foo /><Bar />。你可以这样做:

const condition = 'condition here'

const Comp = condition ? <Foo /> : <Bar />

然后在渲染函数中使用 <Comp />,如下所示:

const render = () => <Comp prop='value' />

使用这种模式的一个常见情况是多种类型的组件共享同一个 props