jsx 和 React 中的动态标签名称

IT技术 reactjs jsx
2021-04-21 00:04:53

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

这是我尝试做的。

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

预期输出:

<h1>Hello</h1>

这是行不通的。有没有可能的方法来做到这一点?

6个回答

无法就地执行此操作,只需将其放入变量中(首字母大写):

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

<CustomTag>Hello</CustomTag>
@zerkms 您知道如何向 CustomTag 添加属性吗?谢谢
2021-06-02 00:04:53
绝对比 容易React.createClass,我更喜欢这种方式。谢谢。
2021-06-03 00:04:53
呵呵。这是如何运作的?如果变量名是小写,它只是将它作为标签插入(例如,如果它是 customtag,我会得到 <customtag>Hello</customtag>)。这在任何地方都有记录吗?
2021-06-03 00:04:53
@萨布丽娜 <CustomTag foo="bar">
2021-06-11 00:04:53
如果组件存储在对象的属性中,则不需要大写首字母。var foo = { bar: CustomTag }; return <foo.bar />工作正常。
2021-06-21 00:04:53

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

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

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

要修复,请强制转换CustomTagkeyof JSX.IntrinsicElements!

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

<CustomTag>Hello</CustomTag>
只是想对此表示感谢。如果这不在这里,我可能会花几个小时来尝试输入。
2021-06-04 00:04:53
你怎么能用 Flow 做到这一点?
2021-06-05 00:04:53
我在typescript,但投射它会出现这个错误: 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'.
2021-06-16 00:04:53

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

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

这避免了必须创建新变量或组件。

带props:

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

文档

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

使用 JSX 编写的代码将转换为使用React.createElement(). React.createElement()如果您使用 JSX,您通常不会直接调用请参阅不使用 JSX 的 React以了解更多信息。

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

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

标题组件:

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>

或者你可以有一个不同的抽象概念,例如你可以定义一个大小props,如:

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(上面由Felix提到)。

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

为了可组合性,props 和 children 都被传递。

见示例