我试图为HTML标题标签(h1, h2, h3等)编写一个React组件,其中标题级别是通过道具指定的。
我试着这样做:
<h{this.props.level}>Hello</h{this.props.level}>
我期望的输出是这样的:
<h1>Hello</h1>
但这行不通。
有什么办法可以做到吗?
我试图为HTML标题标签(h1, h2, h3等)编写一个React组件,其中标题级别是通过道具指定的。
我试着这样做:
<h{this.props.level}>Hello</h{this.props.level}>
我期望的输出是这样的:
<h1>Hello</h1>
但这行不通。
有什么办法可以做到吗?
当前回答
如果你使用的是TypeScript,你会看到这样的错误:
类型'{children:字符串;}'与'IntrinsicAttributes'类型没有共同的属性。ts(2559)
TypeScript不知道CustomTag是一个有效的HTML标记名,并抛出一个无用的错误。
为了解决这个问题,将CustomTag转换为JSX.IntrinsicElements的键!
// var name must start with a capital letter
const CustomTag = `h${this.props.level}` as keyof JSX.IntrinsicElements;
<CustomTag>Hello</CustomTag>
其他回答
如果你使用的是TypeScript,你会看到这样的错误:
类型'{children:字符串;}'与'IntrinsicAttributes'类型没有共同的属性。ts(2559)
TypeScript不知道CustomTag是一个有效的HTML标记名,并抛出一个无用的错误。
为了解决这个问题,将CustomTag转换为JSX.IntrinsicElements的键!
// var name must start with a capital letter
const CustomTag = `h${this.props.level}` as keyof JSX.IntrinsicElements;
<CustomTag>Hello</CustomTag>
所有其他答案都很好,但我要添加一些额外的答案,因为通过这样做:
这样更安全一点。即使你的打字检查失败了 返回一个合适的组件。 它更具有声明性。任何人只要看看这个组件就能知道它能返回什么。 它更灵活,例如取代'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(由Felix在上面提到)。
const Heading = ({level, children, ...props}) => {
return React.createElement('h'.concat(level), props , children)
}
为了可组合性,同时传递了道具和子元素。
看例子
为了完整起见,如果你想使用动态名称,你也可以直接调用React。createElement而不是使用JSX:
React.createElement(`h${this.props.level}`, null, 'Hello')
这避免了必须创建一个新的变量或组件。
道具:
React.createElement(
`h${this.props.level}`,
{
foo: 'bar',
},
'Hello'
)
从文档中可以看出:
创建并返回一个给定类型的新React元素。类型参数可以是标签名字符串(如'div'或'span'),也可以是React组件类型(类或函数)。 用JSX编写的代码将被转换为使用React.createElement()。如果使用JSX,通常不会直接调用React.createElement()。参见React Without JSX了解更多信息。
没有办法做到这一点,只是把它放在一个变量(第一个字母大写):
const CustomTag = `h${this.props.level}`;
<CustomTag>Hello</CustomTag>